Cleanup interfaces (#1401)

RELEASE_NOTES=n/a

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
This commit is contained in:
Dominik Schulz 2020-05-31 09:52:17 +02:00 committed by GitHub
parent d7db829fad
commit e623b38665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 328 additions and 413 deletions

1
go.mod
View File

@ -32,6 +32,7 @@ require (
github.com/schollz/closestmatch v0.0.0-20190308193919-1fbe626be92e
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
github.com/stretchr/testify v1.5.1
github.com/urfave/cli v1.22.4
github.com/urfave/cli/v2 v2.2.0
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd

2
go.sum
View File

@ -92,6 +92,8 @@ github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7i
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/xrash/smetrics v0.0.0-20170218160415-a3153f7040e9 h1:w8V9v0qVympSF6GjdjIyeqR7+EVhAF9CBQmkmW7Zw0w=

View File

@ -123,6 +123,6 @@ func TestCloneGetGitConfig(t *testing.T) {
name, email, err := act.cloneGetGitConfig(ctx, "foobar")
assert.NoError(t, err)
assert.Equal(t, "", name)
assert.Equal(t, "", email)
assert.Equal(t, "0xDEADBEEF", name)
assert.Equal(t, "0xDEADBEEF", email)
}

View File

@ -19,8 +19,8 @@ import (
func (s *Action) GitInit(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
store := c.String("store")
un := detectName(c)
ue := detectEmail(c)
un := termio.DetectName(c.Context, c)
ue := termio.DetectEmail(c.Context, c)
ctx = backend.WithRCSBackendString(ctx, c.String("rcs"))
// default to git

View File

@ -41,8 +41,8 @@ func TestGit(t *testing.T) {
// getUserData
name, email := act.getUserData(ctx, "", "", "")
assert.Equal(t, "", name)
assert.Equal(t, "", email)
assert.Equal(t, "0xDEADBEEF", name)
assert.Equal(t, "0xDEADBEEF", email)
// GitAddRemote
assert.Error(t, act.GitAddRemote(c))

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io/ioutil"
"os"
"github.com/gopasspw/gopass/internal/backend"
"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
@ -55,10 +54,10 @@ func (s *Action) Init(c *cli.Context) error {
alias := c.String("store")
ctx = initParseContext(ctx, c)
if name := detectName(c); name != "" {
if name := termio.DetectName(c.Context, c); name != "" {
ctx = ctxutil.WithUsername(ctx, name)
}
if email := detectEmail(c); email != "" {
if email := termio.DetectEmail(c.Context, c); email != "" {
ctx = ctxutil.WithEmail(ctx, email)
}
inited, err := s.Store.Initialized(ctx)
@ -167,8 +166,8 @@ func (s *Action) printRecipients(ctx context.Context, alias string) {
crypto := s.Store.Crypto(ctx, alias)
for _, recipient := range s.Store.ListRecipients(ctx, alias) {
r := "0x" + recipient
if kl, err := crypto.FindPublicKeys(ctx, recipient); err == nil && len(kl) > 0 {
r = crypto.FormatKey(ctx, kl[0])
if kl, err := crypto.FindRecipients(ctx, recipient); err == nil && len(kl) > 0 {
r = crypto.FormatKey(ctx, kl[0], "")
}
out.Yellow(ctx, " "+r)
}
@ -178,44 +177,17 @@ func (s *Action) getCryptoFor(ctx context.Context, name string) backend.Crypto {
return s.Store.Crypto(ctx, name)
}
func detectName(c *cli.Context) string {
for _, e := range []string{
c.String("name"),
os.Getenv("GIT_AUTHOR_NAME"),
os.Getenv("DEBFULLNAME"),
os.Getenv("USER"),
} {
if e != "" {
return e
}
}
return ""
}
func detectEmail(c *cli.Context) string {
for _, e := range []string{
c.String("email"),
os.Getenv("GIT_AUTHOR_EMAIL"),
os.Getenv("DEBEMAIL"),
os.Getenv("EMAIL"),
} {
if e != "" {
return e
}
}
return ""
}
// InitOnboarding will invoke the onboarding / setup wizard
func (s *Action) InitOnboarding(c *cli.Context) error {
ctx := ctxutil.WithGlobalFlags(c)
remote := c.String("remote")
team := c.String("alias")
create := c.Bool("create")
name := detectName(c)
name := termio.DetectName(c.Context, c)
if name != "" {
ctx = ctxutil.WithUsername(ctx, name)
}
email := detectEmail(c)
email := termio.DetectEmail(c.Context, c)
if email != "" {
ctx = ctxutil.WithEmail(ctx, email)
}
@ -242,7 +214,7 @@ func (s *Action) InitOnboarding(c *cli.Context) error {
out.Yellow(ctx, "No useable crypto keys. Generating new key pair")
ctx := out.AddPrefix(ctx, "[crypto] ")
out.Print(ctx, "Key generation may take up to a few minutes")
if err := s.initCreatePrivateKey(ctx, crypto, name, email); err != nil {
if err := s.initGenerateIdentity(ctx, crypto, name, email); err != nil {
return errors.Wrapf(err, "failed to create new private key")
}
}
@ -282,32 +254,33 @@ func (s *Action) InitOnboarding(c *cli.Context) error {
return nil
}
func (s *Action) initCreatePrivateKey(ctx context.Context, crypto backend.Crypto, name, email string) error {
func (s *Action) initGenerateIdentity(ctx context.Context, crypto backend.Crypto, name, email string) error {
out.Green(ctx, "Creating key pair ...")
out.Yellow(ctx, "WARNING: We are about to generate some GPG keys.")
out.Print(ctx, `However, the GPG program can sometimes lock up, displaying the following:
"We need to generate a lot of random bytes."
If this happens, please see the following tips:
https://github.com/gopasspw/gopass/blob/master/docs/entropy.md`)
if name != "" && email != "" {
ctx := out.AddPrefix(ctx, " ")
passphrase := xkcdgen.Random()
if err := crypto.CreatePrivateKeyBatch(ctx, name, email, passphrase); err != nil {
return errors.Wrapf(err, "failed to create new private key in batch mode")
}
out.Green(ctx, "-> OK")
out.Print(ctx, color.MagentaString("Passphrase: ")+color.HiGreenString(passphrase))
} else {
if want, err := termio.AskForBool(ctx, "Continue?", true); err != nil || !want {
return errors.Wrapf(err, "User aborted")
}
ctx := out.WithPrefix(ctx, " ")
if err := crypto.CreatePrivateKey(ctx); err != nil {
return errors.Wrapf(err, "failed to create new private key in interactive mode")
}
out.Green(ctx, "-> OK")
name, err := termio.AskForString(ctx, "What is your name?", name)
if err != nil {
return err
}
email, err = termio.AskForString(ctx, "What is your email?", email)
if err != nil {
return err
}
if want, err := termio.AskForBool(ctx, "Continue?", true); err != nil || !want {
return errors.Wrapf(err, "User aborted")
}
passphrase := xkcdgen.Random()
if err := crypto.GenerateIdentity(ctx, name, email, passphrase); err != nil {
return errors.Wrapf(err, "failed to create new private key in batch mode")
}
out.Green(ctx, "-> OK")
out.Print(ctx, color.MagentaString("Passphrase: ")+color.HiGreenString(passphrase))
kl, err := crypto.ListIdentities(ctx)
if err != nil {
return errors.Wrapf(err, "failed to list private keys")

View File

@ -45,7 +45,7 @@ func TestInit(t *testing.T) {
crypto := act.Store.Crypto(ctx, "")
assert.Equal(t, true, act.initHasUseablePrivateKeys(ctx, crypto))
assert.Error(t, act.initCreatePrivateKey(ctx, crypto, "foo bar", "foo.bar@example.org"))
assert.Error(t, act.initGenerateIdentity(ctx, crypto, "foo bar", "foo.bar@example.org"))
buf.Reset()
act.printRecipients(ctx, "")

View File

@ -87,7 +87,7 @@ func (s *Action) RecipientsAdd(c *cli.Context) error {
}
for _, r := range recipients {
keys, err := crypto.FindPublicKeys(ctx, r)
keys, err := crypto.FindRecipients(ctx, r)
if err != nil {
out.Cyan(ctx, "WARNING: Failed to list public key '%s': %s", r, err)
if !force {
@ -108,7 +108,7 @@ func (s *Action) RecipientsAdd(c *cli.Context) error {
recp = crypto.Fingerprint(ctx, keys[0])
}
if !termio.AskForConfirmation(ctx, fmt.Sprintf("Do you want to add '%s' as a recipient to the store '%s'?", crypto.FormatKey(ctx, recp), store)) {
if !termio.AskForConfirmation(ctx, fmt.Sprintf("Do you want to add '%s' as a recipient to the store '%s'?", crypto.FormatKey(ctx, recp, ""), store)) {
continue
}
@ -151,7 +151,7 @@ func (s *Action) RecipientsRemove(c *cli.Context) error {
}
for _, r := range recipients {
kl, err := crypto.FindPrivateKeys(ctx, r)
kl, err := crypto.FindIdentities(ctx, r)
if err == nil {
if len(kl) > 0 {
if !termio.AskForConfirmation(ctx, fmt.Sprintf("Do you want to remove yourself (%s) from the recipients?", r)) {
@ -160,7 +160,7 @@ func (s *Action) RecipientsRemove(c *cli.Context) error {
}
}
keys, err := crypto.FindPublicKeys(ctx, r)
keys, err := crypto.FindRecipients(ctx, r)
if err != nil {
out.Cyan(ctx, "WARNING: Failed to list public key '%s': %s", r, err)
if !force {
@ -217,7 +217,7 @@ func (s *Action) RecipientsUpdate(c *cli.Context) error {
}
out.Cyan(ctx, "Please confirm Recipients for %s:", alias)
for _, r := range recp {
out.Print(ctx, "- %s", subs.Crypto().FormatKey(ctx, r))
out.Print(ctx, "- %s", subs.Crypto().FormatKey(ctx, r, ""))
}
if !termio.AskForConfirmation(ctx, fmt.Sprintf("Do you trust these recipients for %s?", alias)) {
continue
@ -244,7 +244,7 @@ func (s *Action) recipientsSelectForRemoval(ctx context.Context, store string) (
ids := s.Store.ListRecipients(ctx, store)
choices := make([]string, 0, len(ids))
for _, id := range ids {
choices = append(choices, crypto.FormatKey(ctx, id))
choices = append(choices, crypto.FormatKey(ctx, id, ""))
}
if len(choices) < 1 {
return nil, nil
@ -265,9 +265,9 @@ func (s *Action) recipientsSelectForAdd(ctx context.Context, store string) ([]st
crypto := s.Store.Crypto(ctx, store)
choices := []string{}
kl, _ := crypto.FindPublicKeys(ctx)
kl, _ := crypto.FindRecipients(ctx)
for _, key := range kl {
choices = append(choices, crypto.FormatKey(ctx, key))
choices = append(choices, crypto.FormatKey(ctx, key, ""))
}
if len(choices) < 1 {
return nil, nil

View File

@ -117,7 +117,7 @@ func (s *Action) syncMount(ctx context.Context, mp string) error {
}
}
debug.Log("syncMount(%s) - exportkeys: %t", mp, ctxutil.IsExportKeys(ctx))
debug.Log("Syncing Mount %s. Exportkeys: %t", mp, ctxutil.IsExportKeys(ctx))
var exported bool
if ctxutil.IsExportKeys(ctx) {
// import keys

View File

@ -43,7 +43,7 @@ func ListPrivateKeys(c *cli.Context) error {
out.Print(ctx, "XC Private Keys:")
for _, key := range kl {
out.Print(ctx, "%s - %s", key, crypto.FormatKey(ctx, key))
out.Print(ctx, "%s - %s", key, crypto.FormatKey(ctx, key, ""))
}
return nil
@ -63,7 +63,7 @@ func ListPublicKeys(c *cli.Context) error {
out.Print(ctx, "XC Public Keys:")
for _, key := range kl {
out.Print(ctx, "%s - %s", key, crypto.FormatKey(ctx, key))
out.Print(ctx, "%s - %s", key, crypto.FormatKey(ctx, key, ""))
}
return nil
@ -102,7 +102,7 @@ func GenerateKeypair(c *cli.Context) error {
}
}
if err := crypto.CreatePrivateKeyBatch(ctx, name, email, pw); err != nil {
if err := crypto.GenerateIdentity(ctx, name, email, pw); err != nil {
return action.ExitError(action.ExitUnknown, err, "failed to create private key: %s", err)
}
return nil

View File

@ -228,7 +228,7 @@ func TestEncryptDecryptFile(t *testing.T) {
crypto = xc.New(td, &fakeAgent{"foobar"})
assert.NoError(t, crypto.CreatePrivateKeyBatch(ctx, "foobar", "foo.bar@example.org", "foobar"))
assert.NoError(t, crypto.GenerateIdentity(ctx, "foobar", "foo.bar@example.org", "foobar"))
app := cli.NewApp()
fs := flag.NewFlagSet("default", flag.ContinueOnError)
@ -276,7 +276,7 @@ func TestEncryptDecryptStream(t *testing.T) {
crypto = xc.New(td, &fakeAgent{"foobar"})
assert.NoError(t, crypto.CreatePrivateKeyBatch(ctx, "foobar", "foo.bar@example.org", "foobar"))
assert.NoError(t, crypto.GenerateIdentity(ctx, "foobar", "foo.bar@example.org", "foobar"))
app := cli.NewApp()
fs := flag.NewFlagSet("default", flag.ContinueOnError)

View File

@ -35,17 +35,14 @@ type Keyring interface {
ListRecipients(ctx context.Context) ([]string, error)
ListIdentities(ctx context.Context) ([]string, error)
FindPublicKeys(ctx context.Context, needles ...string) ([]string, error)
FindPrivateKeys(ctx context.Context, needles ...string) ([]string, error)
FindRecipients(ctx context.Context, needles ...string) ([]string, error)
FindIdentities(ctx context.Context, needles ...string) ([]string, error)
FormatKey(ctx context.Context, id string) string
NameFromKey(ctx context.Context, id string) string
EmailFromKey(ctx context.Context, id string) string
Fingerprint(ctx context.Context, id string) string
FormatKey(ctx context.Context, id, tpl string) string
ReadNamesFromKey(ctx context.Context, buf []byte) ([]string, error)
CreatePrivateKeyBatch(ctx context.Context, name, email, passphrase string) error
CreatePrivateKey(ctx context.Context) error
GenerateIdentity(ctx context.Context, name, email, passphrase string) error
}
// Crypto is a crypto backend
@ -95,14 +92,14 @@ func DetectCrypto(ctx context.Context, storage Storage) (Crypto, error) {
})
for _, id := range bes {
be := cryptoRegistry[id]
debug.Log("DetectCrypto(%s) - trying %s", storage, be)
debug.Log("Trying %s for %s", be, storage)
if err := be.Handles(storage); err != nil {
debug.Log("failed to use crypto %s for %s", id, storage)
continue
}
debug.Log("DetectCrypto(%s) - using %s", storage, be)
debug.Log("Using %s for %s", be, storage)
return be.New(ctx)
}
debug.Log("DetectCrypto(%s) - no valid crypto provider found", storage)
debug.Log("No valid crypto provider found for %s", storage)
return nil, nil
}

View File

@ -14,7 +14,6 @@ import (
"github.com/google/go-github/github"
"github.com/gopasspw/gopass/internal/cache"
"github.com/gopasspw/gopass/internal/debug"
"github.com/gopasspw/gopass/internal/out"
"github.com/gopasspw/gopass/internal/termio"
"github.com/gopasspw/gopass/pkg/fsutil"
)
@ -131,7 +130,7 @@ func (a *Age) encrypt(ctx context.Context, plaintext []byte, args ...string) ([]
cmd.Stdout = buf
cmd.Stderr = os.Stderr
debug.Log("age.encrypt: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
err := cmd.Run()
return buf.Bytes(), err
}
@ -150,7 +149,7 @@ func (a *Age) Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error) {
args := []string{}
for _, k := range a.listPrivateKeyFiles(ctx) {
if k == "native-keyring" {
debug.Log("age.Decrypt - decrypting native keyring for file decrypt")
debug.Log("decrypting native keyring for file decrypt")
td, err := ioutil.TempDir("", "gpa")
if err != nil {
return nil, err
@ -175,7 +174,7 @@ func (a *Age) decrypt(ctx context.Context, ciphertext []byte, args ...string) ([
cmd.Stdin = bytes.NewReader(ciphertext)
cmd.Stderr = os.Stderr
debug.Log("age.Decrypt: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
return cmd.Output()
}
@ -195,8 +194,8 @@ func (a *Age) decryptFileTo(ctx context.Context, src, dst string) error {
return ioutil.WriteFile(dst, buf, 0600)
}
// CreatePrivateKeyBatch will create a new native private key
func (a *Age) CreatePrivateKeyBatch(ctx context.Context, name, email, pw string) error {
// GenerateIdentity will create a new native private key
func (a *Age) GenerateIdentity(ctx context.Context, name, email, pw string) error {
buf := &bytes.Buffer{}
cmd := exec.CommandContext(ctx, "age-keygen")
cmd.Stdout = buf
@ -223,7 +222,7 @@ func (a *Age) CreatePrivateKeyBatch(ctx context.Context, name, email, pw string)
return err
}
debug.Log("age.CreatePrivateKey: %s", buf.String())
debug.Log("%s", buf.String())
if err := os.MkdirAll(filepath.Dir(a.keyring), 0700); err != nil {
return err
@ -233,22 +232,6 @@ func (a *Age) CreatePrivateKeyBatch(ctx context.Context, name, email, pw string)
return a.encryptFile(ctx, a.keyring, buf.Bytes())
}
// CreatePrivateKey is TODO
func (a *Age) CreatePrivateKey(ctx context.Context) error {
out.Print(ctx, "Generating new Age keypair ...")
name, err := termio.AskForString(ctx, "What is your name?", "")
if err != nil {
return err
}
email, err := termio.AskForString(ctx, "What is your email?", "")
if err != nil {
return err
}
return a.CreatePrivateKeyBatch(ctx, name, email, "unused")
}
// ListIdentities is TODO
func (a *Age) ListIdentities(ctx context.Context) ([]string, error) {
native, err := a.getNativeKeypairs(ctx)
@ -338,11 +321,15 @@ func (a *Age) getNativeKeypairs(ctx context.Context) (map[string]string, error)
_, err := os.Stat(a.keyring)
if os.IsNotExist(err) {
debug.Log("No native age key found. Generating ...")
if err := a.CreatePrivateKey(ctx); err != nil {
pw, err := termio.AskForPassword(ctx, "Please enter a passphrase for your new Age key")
if err != nil {
return nil, err
}
if err := a.GenerateIdentity(ctx, termio.DetectName(ctx, nil), termio.DetectEmail(ctx, nil), pw); err != nil {
return nil, err
}
}
debug.Log("age.getNativeKeypairs - decrypting keyring")
debug.Log("decrypting keyring")
buf, err := a.decryptFile(ctx, a.keyring)
if err != nil {
return nil, err
@ -385,8 +372,8 @@ func (a *Age) getAllKeypairs(ctx context.Context) (map[string]string, error) {
return keys, nil
}
// FindPublicKeys it TODO
func (a *Age) FindPublicKeys(ctx context.Context, keys ...string) ([]string, error) {
// FindRecipients it TODO
func (a *Age) FindRecipients(ctx context.Context, keys ...string) ([]string, error) {
nk, err := a.getAllKeypairs(ctx)
if err != nil {
return nil, err
@ -400,7 +387,7 @@ func (a *Age) FindPublicKeys(ctx context.Context, keys ...string) ([]string, err
return matches, nil
}
// FindPrivateKeys is TODO
func (a *Age) FindPrivateKeys(ctx context.Context, keys ...string) ([]string, error) {
return a.FindPublicKeys(ctx, keys...)
// FindIdentities is TODO
func (a *Age) FindIdentities(ctx context.Context, keys ...string) ([]string, error) {
return a.FindRecipients(ctx, keys...)
}

View File

@ -5,22 +5,12 @@ import (
"fmt"
)
// EmailFromKey is TODO
func (a *Age) EmailFromKey(context.Context, string) string {
return ""
}
// NameFromKey is TODO
func (a *Age) NameFromKey(context.Context, string) string {
return ""
}
// FormatKey is TODO
func (a *Age) FormatKey(ctx context.Context, id string) string {
func (a *Age) FormatKey(ctx context.Context, id, tpl string) string {
return id
}
// Fingerprint is TODO
// Fingerprint return the id
func (a *Age) Fingerprint(ctx context.Context, id string) string {
return id
}
@ -30,11 +20,6 @@ func (a *Age) ImportPublicKey(ctx context.Context, buf []byte) error {
return nil
}
// Sign is TODO
func (a *Age) Sign(ctx context.Context, in string, sigf string) error {
return fmt.Errorf("not implemented")
}
// ListRecipients is TODO
func (a *Age) ListRecipients(context.Context) ([]string, error) {
return nil, fmt.Errorf("not implemented")

View File

@ -17,7 +17,7 @@ func (g *GPG) ExportPublicKey(ctx context.Context, id string) ([]byte, error) {
args := append(g.args, "--armor", "--export", id)
cmd := exec.CommandContext(ctx, g.binary, args...)
debug.Log("gpg.ExportPublicKey: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
out, err := cmd.Output()
if err != nil {
return nil, errors.Wrapf(err, "failed to run command '%s %+v'", cmd.Path, cmd.Args)

View File

@ -3,15 +3,14 @@ package cli
import (
"bytes"
"context"
"os"
"os/exec"
"github.com/gopasspw/gopass/internal/debug"
"github.com/pkg/errors"
)
// CreatePrivateKeyBatch will create a new GPG keypair in batch mode
func (g *GPG) CreatePrivateKeyBatch(ctx context.Context, name, email, passphrase string) error {
// GenerateIdentity will create a new GPG keypair in batch mode
func (g *GPG) GenerateIdentity(ctx context.Context, name, email, passphrase string) error {
buf := &bytes.Buffer{}
// https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=de0f21ccba60c3037c2a155156202df1cd098507;hb=refs/heads/STABLE-BRANCH-1-4#l716
_, _ = buf.WriteString(`%echo Generating a RSA/RSA key pair
@ -31,7 +30,7 @@ Expire-Date: 0
cmd.Stdout = nil
cmd.Stderr = nil
debug.Log("gpg.CreatePrivateKeyBatch: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "failed to run command: '%s %+v'", cmd.Path, cmd.Args)
}
@ -39,21 +38,3 @@ Expire-Date: 0
g.pubKeys = nil
return nil
}
// CreatePrivateKey will create a new GPG key in interactive mode
func (g *GPG) CreatePrivateKey(ctx context.Context) error {
args := []string{"--gen-key"}
cmd := exec.CommandContext(ctx, g.binary, args...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
debug.Log("gpg.CreatePrivateKey: %s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return errors.Wrapf(err, "failed to run command: '%s %+v'", cmd.Path, cmd.Args)
}
g.privKeys = nil
g.pubKeys = nil
return nil
}

View File

@ -9,12 +9,11 @@ import (
"github.com/stretchr/testify/assert"
)
func TestCreatePrivateKey(t *testing.T) {
func TestGenerateIdentity(t *testing.T) {
ctx := context.Background()
g := &GPG{}
g.binary = "true"
assert.NoError(t, g.CreatePrivateKeyBatch(ctx, "foo", "foo@bar.com", "bar"))
assert.NoError(t, g.CreatePrivateKey(ctx))
assert.NoError(t, g.GenerateIdentity(ctx, "foo", "foo@bar.com", "bar"))
}

View File

@ -7,13 +7,12 @@ import (
"github.com/stretchr/testify/assert"
)
func TestCreatePrivateKey(t *testing.T) {
func TestGenerateIdentity(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
g := &GPG{}
g.binary = "rundll32"
assert.NoError(t, g.CreatePrivateKeyBatch(ctx, "foo", "foo@bar.com", "bar"))
assert.NoError(t, g.CreatePrivateKey(ctx))
assert.NoError(t, g.GenerateIdentity(ctx, "foo", "foo@bar.com", "bar"))
cancel()
}

View File

@ -12,6 +12,7 @@ import (
"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
"github.com/gopasspw/gopass/internal/debug"
"github.com/gopasspw/gopass/internal/out"
lru "github.com/hashicorp/golang-lru"
)
@ -82,7 +83,7 @@ func (g *GPG) RecipientIDs(ctx context.Context, buf []byte) ([]string, error) {
args := []string{"--batch", "--list-only", "--list-packets", "--no-default-keyring", "--secret-keyring", "/dev/null"}
cmd := exec.CommandContext(ctx, g.binary, args...)
cmd.Stdin = bytes.NewReader(buf)
debug.Log("gpg.GetRecipients: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
cmdout, err := cmd.CombinedOutput()
if err != nil {
@ -92,7 +93,7 @@ func (g *GPG) RecipientIDs(ctx context.Context, buf []byte) ([]string, error) {
scanner := bufio.NewScanner(bytes.NewBuffer(cmdout))
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
debug.Log("gpg Output: %s", line)
debug.Log("GPG Output: %s", line)
if !strings.HasPrefix(line, ":pubkey enc packet:") {
continue
}
@ -120,6 +121,13 @@ func (g *GPG) Encrypt(ctx context.Context, plaintext []byte, recipients []string
args = append(args, "--trust-model=always")
}
for _, r := range recipients {
kl, err := g.listKeys(ctx, "public", r)
if err != nil {
debug.Log("Failed to check key %s. Adding anyway. %s", err)
} else if len(kl.UseableKeys(gpg.IsAlwaysTrust(ctx))) < 1 {
out.Red(ctx, "Not using expired key %s for encryption", r)
continue
}
args = append(args, "--recipient", r)
}
@ -130,7 +138,7 @@ func (g *GPG) Encrypt(ctx context.Context, plaintext []byte, recipients []string
cmd.Stdout = buf
cmd.Stderr = os.Stderr
debug.Log("gpg.Encrypt: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
err := cmd.Run()
return buf.Bytes(), err
}
@ -142,7 +150,7 @@ func (g *GPG) Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error) {
cmd.Stdin = bytes.NewReader(ciphertext)
cmd.Stderr = os.Stderr
debug.Log("gpg.Decrypt: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
return cmd.Output()
}

View File

@ -6,6 +6,7 @@ import (
"fmt"
"os/exec"
"strings"
"text/template"
"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
"github.com/gopasspw/gopass/internal/debug"
@ -24,7 +25,7 @@ func (g *GPG) listKeys(ctx context.Context, typ string, search ...string) (gpg.K
var errBuf = bytes.Buffer{}
cmd.Stderr = &errBuf
debug.Log("gpg.listKeys: %s %+v\n", cmd.Path, cmd.Args)
debug.Log("%s %+v\n", cmd.Path, cmd.Args)
cmdout, err := cmd.Output()
if err != nil {
if bytes.Contains(cmdout, []byte("secret key not available")) {
@ -50,11 +51,11 @@ func (g *GPG) ListRecipients(ctx context.Context) ([]string, error) {
if gpg.IsAlwaysTrust(ctx) {
return g.pubKeys.Recipients(), nil
}
return g.pubKeys.UseableKeys().Recipients(), nil
return g.pubKeys.UseableKeys(gpg.IsAlwaysTrust(ctx)).Recipients(), nil
}
// FindPublicKeys searches for the given public keys
func (g *GPG) FindPublicKeys(ctx context.Context, search ...string) ([]string, error) {
// FindRecipients searches for the given public keys
func (g *GPG) FindRecipients(ctx context.Context, search ...string) ([]string, error) {
kl, err := g.listKeys(ctx, "public", search...)
if err != nil || kl == nil {
return nil, err
@ -62,7 +63,7 @@ func (g *GPG) FindPublicKeys(ctx context.Context, search ...string) ([]string, e
if gpg.IsAlwaysTrust(ctx) {
return kl.Recipients(), nil
}
return kl.UseableKeys().Recipients(), nil
return kl.UseableKeys(gpg.IsAlwaysTrust(ctx)).Recipients(), nil
}
// ListIdentities returns a parsed list of GPG secret keys
@ -77,11 +78,11 @@ func (g *GPG) ListIdentities(ctx context.Context) ([]string, error) {
if gpg.IsAlwaysTrust(ctx) {
return g.privKeys.Recipients(), nil
}
return g.privKeys.UseableKeys().Recipients(), nil
return g.privKeys.UseableKeys(gpg.IsAlwaysTrust(ctx)).Recipients(), nil
}
// FindPrivateKeys searches for the given private keys
func (g *GPG) FindPrivateKeys(ctx context.Context, search ...string) ([]string, error) {
// FindIdentities searches for the given private keys
func (g *GPG) FindIdentities(ctx context.Context, search ...string) ([]string, error) {
kl, err := g.listKeys(ctx, "secret", search...)
if err != nil || kl == nil {
return nil, err
@ -89,7 +90,7 @@ func (g *GPG) FindPrivateKeys(ctx context.Context, search ...string) ([]string,
if gpg.IsAlwaysTrust(ctx) {
return kl.Recipients(), nil
}
return kl.UseableKeys().Recipients(), nil
return kl.UseableKeys(gpg.IsAlwaysTrust(ctx)).Recipients(), nil
}
func (g *GPG) findKey(ctx context.Context, id string) gpg.Key {
@ -106,22 +107,30 @@ func (g *GPG) findKey(ctx context.Context, id string) gpg.Key {
}
}
// EmailFromKey extracts the email from a key id
func (g *GPG) EmailFromKey(ctx context.Context, id string) string {
return g.findKey(ctx, id).Identity().Email
}
// NameFromKey extracts the name from a key id
func (g *GPG) NameFromKey(ctx context.Context, id string) string {
return g.findKey(ctx, id).Identity().Name
}
// FormatKey formats the details of a key id
func (g *GPG) FormatKey(ctx context.Context, id string) string {
return g.findKey(ctx, id).OneLine()
}
// Fingerprint returns the full-length native fingerprint
// Fingerprint returns the fingerprint
func (g *GPG) Fingerprint(ctx context.Context, id string) string {
return g.findKey(ctx, id).Fingerprint
}
// FormatKey formats the details of a key id
// Examples:
// - NameFromKey: {{ .Name }}
// - EmailFromKey: {{ .Email }}
func (g *GPG) FormatKey(ctx context.Context, id, tpl string) string {
if tpl == "" {
return g.findKey(ctx, id).OneLine()
}
tmpl, err := template.New(tpl).Parse(tpl)
if err != nil {
return ""
}
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, g.findKey(ctx, id).Identity()); err != nil {
debug.Log("Failed to render template '%s': %s", tpl, err)
return ""
}
return buf.String()
}

View File

@ -20,10 +20,13 @@ type Key struct {
}
// IsUseable returns true if GPG would assume this key is useable for encryption
func (k Key) IsUseable() bool {
func (k Key) IsUseable(alwaysTrust bool) bool {
if !k.ExpirationDate.IsZero() && k.ExpirationDate.Before(time.Now()) {
return false
}
if alwaysTrust {
return true
}
switch k.Validity {
case "m":
return true

View File

@ -21,11 +21,11 @@ func (kl KeyList) Recipients() []string {
}
// UseableKeys returns the list of useable (valid keys)
func (kl KeyList) UseableKeys() KeyList {
func (kl KeyList) UseableKeys(alwaysTrust bool) KeyList {
nkl := make(KeyList, 0, len(kl))
sort.Sort(kl)
for _, k := range kl {
if !k.IsUseable() {
if !k.IsUseable(alwaysTrust) {
continue
}
nkl = append(nkl, k)
@ -34,10 +34,10 @@ func (kl KeyList) UseableKeys() KeyList {
}
// UnusableKeys returns the list of unusable keys (invalid keys)
func (kl KeyList) UnusableKeys() KeyList {
func (kl KeyList) UnusableKeys(alwaysTrust bool) KeyList {
nkl := make(KeyList, 0, len(kl))
for _, k := range kl {
if k.IsUseable() {
if k.IsUseable(alwaysTrust) {
continue
}
nkl = append(nkl, k)

View File

@ -21,8 +21,8 @@ func TestKeyList(t *testing.T) {
"0x62AF4031C82E2019",
"0x62AF4031C82E0039",
}, kl.Recipients())
assert.Equal(t, []string{"0x62AF4031C82E0019", "0x62AF4031C82E0039"}, kl.UseableKeys().Recipients())
assert.Equal(t, []string{"0x62AF4031C82E2019"}, kl.UnusableKeys().Recipients())
assert.Equal(t, []string{"0x62AF4031C82E0019", "0x62AF4031C82E0039"}, kl.UseableKeys(false).Recipients())
assert.Equal(t, []string{"0x62AF4031C82E2019"}, kl.UnusableKeys(false).Recipients())
// search by email
k, err := kl.FindKey("jim.doe@example.org")

View File

@ -67,7 +67,7 @@ func TestKey(t *testing.T) {
assert.Equal(t, "(invalid:)", k.OneLine())
assert.Equal(t, "", k.Identity().Name)
k = genTestKey()
assert.Equal(t, k.IsUseable(), true)
assert.Equal(t, k.IsUseable(false), true)
assert.Equal(t, "sec 2048D/0x62AF4031C82E0039 2018-01-01 [expires: 2218-01-01]\n Key fingerprint = 25FF1614B8F87B52FFFF99B962AF4031C82E0039\nuid John Doe (johnny) <john.doe@example.org>", k.String())
assert.Equal(t, "0x62AF4031C82E0039 - John Doe (johnny) <john.doe@example.org>", k.OneLine())
assert.Equal(t, "0x62AF4031C82E0039", k.ID())
@ -100,7 +100,7 @@ func TestUseability(t *testing.T) {
Validity: "z",
},
} {
assert.Equal(t, false, k.IsUseable())
assert.Equal(t, false, k.IsUseable(false))
}
// valid
for _, k := range []Key{
@ -117,6 +117,6 @@ func TestUseability(t *testing.T) {
Validity: "u",
},
} {
assert.Equal(t, true, k.IsUseable())
assert.Equal(t, true, k.IsUseable(false))
}
}

View File

@ -4,9 +4,7 @@ package plain
import (
"context"
"crypto/sha256"
"fmt"
"io/ioutil"
"strings"
"time"
@ -59,8 +57,8 @@ func (m *Mocker) ListRecipients(context.Context) ([]string, error) {
return staticPrivateKeyList.Recipients(), nil
}
// FindPublicKeys does nothing
func (m *Mocker) FindPublicKeys(ctx context.Context, keys ...string) ([]string, error) {
// FindRecipients does nothing
func (m *Mocker) FindRecipients(ctx context.Context, keys ...string) ([]string, error) {
rs := staticPrivateKeyList.Recipients()
res := make([]string, 0, len(rs))
for _, r := range rs {
@ -78,9 +76,9 @@ func (m *Mocker) ListIdentities(context.Context) ([]string, error) {
return staticPrivateKeyList.Recipients(), nil
}
// FindPrivateKeys does nothing
func (m *Mocker) FindPrivateKeys(ctx context.Context, keys ...string) ([]string, error) {
return m.FindPublicKeys(ctx, keys...)
// FindIdentities does nothing
func (m *Mocker) FindIdentities(ctx context.Context, keys ...string) ([]string, error) {
return m.FindRecipients(ctx, keys...)
}
// RecipientIDs does nothing
@ -118,67 +116,18 @@ func (m *Mocker) Binary() string {
return "gpg"
}
// Sign writes the hashsum to the given file
func (m *Mocker) Sign(in string, sigf string) error {
buf, err := ioutil.ReadFile(in)
if err != nil {
return err
}
sum := sha256.New()
_, _ = sum.Write(buf)
hexsum := fmt.Sprintf("%X", sum.Sum(nil))
return ioutil.WriteFile(sigf, []byte(hexsum), 0644)
}
// Verify does a pseudo-verification
func (m *Mocker) Verify(sigf string, in string) error {
sigb, err := ioutil.ReadFile(sigf)
if err != nil {
return err
}
buf, err := ioutil.ReadFile(in)
if err != nil {
return err
}
sum := sha256.New()
_, _ = sum.Write(buf)
hexsum := fmt.Sprintf("%X", sum.Sum(nil))
if string(sigb) != hexsum {
return fmt.Errorf("hashsum mismatch")
}
return nil
}
// CreatePrivateKey is not implemented
func (m *Mocker) CreatePrivateKey(ctx context.Context) error {
// GenerateIdentity is not implemented
func (m *Mocker) GenerateIdentity(ctx context.Context, name, email, pw string) error {
return fmt.Errorf("not yet implemented")
}
// CreatePrivateKeyBatch is not implemented
func (m *Mocker) CreatePrivateKeyBatch(ctx context.Context, name, email, pw string) error {
return fmt.Errorf("not yet implemented")
}
// EmailFromKey returns nothing
func (m *Mocker) EmailFromKey(context.Context, string) string {
return ""
}
// NameFromKey returns nothing
func (m *Mocker) NameFromKey(context.Context, string) string {
return ""
}
// FormatKey returns the id
func (m *Mocker) FormatKey(ctx context.Context, id string) string {
// Fingerprint returns thd id
func (m *Mocker) Fingerprint(ctx context.Context, id string) string {
return id
}
// Fingerprint returns the full-length native fingerprint
func (m *Mocker) Fingerprint(ctx context.Context, id string) string {
// FormatKey returns the id
func (m *Mocker) FormatKey(ctx context.Context, id, tpl string) string {
return id
}

View File

@ -4,7 +4,6 @@ import (
"context"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/gopasspw/gopass/pkg/ctxutil"
@ -47,18 +46,17 @@ func TestPlain(t *testing.T) {
assert.Equal(t, "gpg", m.Binary())
assert.Error(t, m.CreatePrivateKey(ctx))
assert.Error(t, m.CreatePrivateKeyBatch(ctx, "", "", ""))
assert.Error(t, m.GenerateIdentity(ctx, "", "", ""))
kl, err = m.FindPublicKeys(ctx)
kl, err = m.FindRecipients(ctx)
assert.NoError(t, err)
assert.Empty(t, kl, "FindPublicKeys()")
assert.Empty(t, kl, "FindRecipients()")
kl, err = m.FindPublicKeys(ctx, "0xDEADBEEF")
kl, err = m.FindRecipients(ctx, "0xDEADBEEF")
assert.NoError(t, err)
assert.NotEmpty(t, kl, "FindPublicKeys(0xDEADBEEF)")
assert.NotEmpty(t, kl, "FindRecipients(0xDEADBEEF)")
_, err = m.FindPrivateKeys(ctx)
_, err = m.FindIdentities(ctx)
assert.NoError(t, err)
buf, err = m.ExportPublicKey(ctx, "")
@ -66,9 +64,7 @@ func TestPlain(t *testing.T) {
assert.NoError(t, m.ImportPublicKey(ctx, buf))
assert.Equal(t, semver.Version{}, m.Version(ctx))
assert.Equal(t, "", m.EmailFromKey(ctx, ""))
assert.Equal(t, "", m.NameFromKey(ctx, ""))
assert.Equal(t, "", m.FormatKey(ctx, ""))
assert.Equal(t, "", m.FormatKey(ctx, "", ""))
assert.Equal(t, "", m.Fingerprint(ctx, ""))
assert.Nil(t, m.Initialized(ctx))
assert.Equal(t, "plain", m.Name())
@ -86,27 +82,3 @@ func TestLoader(t *testing.T) {
assert.Equal(t, name, l.String())
assert.Equal(t, "plain", b.Name())
}
func TestSignVerify(t *testing.T) {
td, err := ioutil.TempDir("", "gopass-")
assert.NoError(t, err)
defer func() {
_ = os.RemoveAll(td)
}()
m := New()
in := filepath.Join(td, "in")
assert.NoError(t, ioutil.WriteFile(in, []byte("in"), 0644))
sigf := filepath.Join(td, "sigf")
assert.NoError(t, m.Sign(in, sigf))
assert.NoError(t, m.Verify(sigf, in))
assert.Error(t, m.Sign("/tmp", sigf))
assert.Error(t, m.Verify(sigf, "/tmp"))
assert.Error(t, m.Verify("/tmp", in))
assert.NoError(t, ioutil.WriteFile(sigf, []byte("in"), 0644))
assert.Error(t, m.Verify(sigf, in))
}

View File

@ -1,13 +1,15 @@
package xc
import (
"bytes"
"context"
"fmt"
"sort"
"strings"
"text/template"
"github.com/gopasspw/gopass/internal/backend/crypto/xc/keyring"
"github.com/gopasspw/gopass/internal/backend/crypto/xc/xcpb"
"github.com/gopasspw/gopass/internal/debug"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
@ -49,8 +51,8 @@ func (x *XC) ListIdentities(ctx context.Context) ([]string, error) {
return x.secring.KeyIDs(), nil
}
// FindPublicKeys finds all matching public keys
func (x *XC) FindPublicKeys(ctx context.Context, search ...string) ([]string, error) {
// FindRecipients finds all matching public keys
func (x *XC) FindRecipients(ctx context.Context, search ...string) ([]string, error) {
ids := make([]string, 0, 1)
candidates, _ := x.ListRecipients(ctx)
for _, needle := range search {
@ -64,8 +66,8 @@ func (x *XC) FindPublicKeys(ctx context.Context, search ...string) ([]string, er
return ids, nil
}
// FindPrivateKeys finds all matching private keys
func (x *XC) FindPrivateKeys(ctx context.Context, search ...string) ([]string, error) {
// FindIdentities finds all matching private keys
func (x *XC) FindIdentities(ctx context.Context, search ...string) ([]string, error) {
ids := make([]string, 0, 1)
candidates, _ := x.ListIdentities(ctx)
for _, needle := range search {
@ -79,46 +81,43 @@ func (x *XC) FindPrivateKeys(ctx context.Context, search ...string) ([]string, e
return ids, nil
}
// FormatKey formats a key
func (x *XC) FormatKey(ctx context.Context, id string) string {
func (x *XC) findID(id string) *xcpb.Identity {
if key := x.pubring.Get(id); key != nil {
return id + " - " + key.Identity.ID()
return key.Identity
}
if key := x.secring.Get(id); key != nil {
return id + " - " + key.PublicKey.Identity.ID()
return key.PublicKey.Identity
}
return id
return &xcpb.Identity{}
}
// NameFromKey extracts the name from a key
func (x *XC) NameFromKey(ctx context.Context, id string) string {
if key := x.pubring.Get(id); key != nil {
return key.Identity.Name
}
if key := x.secring.Get(id); key != nil {
return key.PublicKey.Identity.Name
}
return id
}
// EmailFromKey extracts the email from a key
func (x *XC) EmailFromKey(ctx context.Context, id string) string {
if key := x.pubring.Get(id); key != nil {
return key.Identity.Email
}
if key := x.secring.Get(id); key != nil {
return key.PublicKey.Identity.Email
}
return id
}
// Fingerprint returns the full-length native fingerprint
// Fingerprint returns the id
func (x *XC) Fingerprint(ctx context.Context, id string) string {
return id
}
// CreatePrivateKeyBatch creates a new keypair
func (x *XC) CreatePrivateKeyBatch(ctx context.Context, name, email, passphrase string) error {
// FormatKey formats a key
func (x *XC) FormatKey(ctx context.Context, id, tpl string) string {
if tpl == "" {
tpl = "{{ .ID }} - {{ .Name }} <{{ .Email }}>"
}
tmpl, err := template.New(tpl).Parse(tpl)
if err != nil {
return ""
}
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, x.findID(id)); err != nil {
debug.Log("Failed to render template '%s': %s", tpl, err)
return ""
}
return buf.String()
}
// GenerateIdentity creates a new keypair
func (x *XC) GenerateIdentity(ctx context.Context, name, email, passphrase string) error {
k, err := keyring.GenerateKeypair(passphrase)
if err != nil {
return errors.Wrapf(err, "failed to generate keypair: %s", err)
@ -130,8 +129,3 @@ func (x *XC) CreatePrivateKeyBatch(ctx context.Context, name, email, passphrase
}
return x.secring.Save()
}
// CreatePrivateKey is not implemented
func (x *XC) CreatePrivateKey(ctx context.Context) error {
return fmt.Errorf("not yet implemented")
}

View File

@ -13,7 +13,7 @@ import (
"github.com/stretchr/testify/require"
)
func TestCreatePrivateKeyBatch(t *testing.T) {
func TestGenerateIdentity(t *testing.T) {
ctx := context.Background()
td, err := ioutil.TempDir("", "gopass-")
@ -38,7 +38,7 @@ func TestCreatePrivateKeyBatch(t *testing.T) {
client: &fakeAgent{passphrase},
}
assert.NoError(t, xc.CreatePrivateKeyBatch(ctx, "foo", "bar@example.org", passphrase))
assert.NoError(t, xc.GenerateIdentity(ctx, "foo", "bar@example.org", passphrase))
pubKeys, err := xc.ListRecipients(ctx)
require.NoError(t, err)
@ -50,25 +50,15 @@ func TestCreatePrivateKeyBatch(t *testing.T) {
assert.Equal(t, len(pubKeys), len(privKeys))
id := pubKeys[0]
assert.Contains(t, xc.FormatKey(ctx, id), "foo <bar@example.org>")
assert.Equal(t, "foo", xc.NameFromKey(ctx, id))
assert.Equal(t, "bar@example.org", xc.EmailFromKey(ctx, id))
assert.Contains(t, xc.FormatKey(ctx, id, ""), "foo <bar@example.org>")
pubKeys, err = xc.FindPublicKeys(ctx, id)
pubKeys, err = xc.FindRecipients(ctx, id)
assert.NoError(t, err)
assert.Equal(t, []string{id}, pubKeys)
privKeys, err = xc.FindPrivateKeys(ctx, id)
privKeys, err = xc.FindIdentities(ctx, id)
assert.NoError(t, err)
assert.Equal(t, []string{id}, privKeys)
assert.NoError(t, xc.RemoveKey(id))
}
func TestCreatePrivateKey(t *testing.T) {
ctx := context.Background()
var x *XC
assert.Error(t, x.CreatePrivateKey(ctx))
}

View File

@ -44,6 +44,7 @@ type RCS interface {
GetRevision(ctx context.Context, name, revision string) ([]byte, error)
Status(ctx context.Context) ([]byte, error)
Compact(ctx context.Context) error
}
// Revision is a SCM revision
@ -87,15 +88,15 @@ func DetectRCS(ctx context.Context, path string) (RCS, error) {
})
for _, id := range bes {
be := rcsRegistry[id]
debug.Log("DetectRCS(%s) - trying %s", path, be)
debug.Log("Trying %s for %s", be, path)
if err := be.Handles(path); err != nil {
debug.Log("failed to use RCS %s for %s", id, path)
continue
}
debug.Log("DetectRCS(%s) - using %s", path, be)
debug.Log("Using %s for %s", be, path)
return be.Open(ctx, path)
}
debug.Log("DetectRCS(%s) - no supported RCS found. using NOOP", path)
debug.Log("No supported RCS found for %s. using NOOP", path)
return rcsRegistry[Noop].InitRCS(ctx, path)
}

View File

@ -88,7 +88,7 @@ func (g *Git) ConfigGet(ctx context.Context, key string) (string, error) {
cmd.Stdout = buf
cmd.Stderr = os.Stderr
debug.Log("store.gitConfigGet: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return "", err
}
@ -109,7 +109,7 @@ func (g *Git) ConfigList(ctx context.Context) (map[string]string, error) {
cmd.Stdout = buf
cmd.Stderr = os.Stderr
debug.Log("store.gitConfigList: %s %+v", cmd.Path, cmd.Args)
debug.Log("%s %+v", cmd.Path, cmd.Args)
if err := cmd.Run(); err != nil {
return nil, err
}

View File

@ -365,3 +365,8 @@ func (g *Git) Status(ctx context.Context) ([]byte, error) {
}
return stdout, nil
}
// Compact will run git gc
func (g *Git) Compact(ctx context.Context) error {
return g.Cmd(ctx, "gitGC", "gc", "--aggressive")
}

View File

@ -89,3 +89,8 @@ func (g *Noop) GetRevision(context.Context, string, string) ([]byte, error) {
func (g *Noop) Status(context.Context) ([]byte, error) {
return []byte(""), nil
}
// Compact is not implemented
func (g *Noop) Compact(context.Context) error {
return nil
}

View File

@ -70,12 +70,12 @@ func DetectStorage(ctx context.Context, path string) (Storage, error) {
})
for _, id := range bes {
be := storageRegistry[id]
debug.Log("DetectStorage(%s) - trying %s", path, be)
debug.Log("Trying %s for %s", be, path)
if err := be.Handles(path); err != nil {
debug.Log("failed to use %s for %s: %s", id, path, err)
continue
}
debug.Log("DetectStorage(%s) - using %s", path, be)
debug.Log("Using %s for %s", be, path)
return be.New(ctx, path)
}
return storageRegistry[FS].Init(ctx, path)

View File

@ -23,7 +23,7 @@ func (s *Store) Fsck(ctx context.Context) error {
dirs := make(map[string]struct{}, len(entries))
for _, entry := range entries {
pcb()
debug.Log("file.Fsck() - Checking %s", entry)
debug.Log("Checking %s", entry)
filename := filepath.Join(s.path, entry)
dirs[filepath.Dir(filename)] = struct{}{}

View File

@ -40,7 +40,7 @@ func (s *Store) Get(ctx context.Context, name string) ([]byte, error) {
name = filepath.FromSlash(name)
}
path := filepath.Join(s.path, filepath.Clean(name))
debug.Log("fs.Get(%s) - %s", name, path)
debug.Log("Reading %s from %s", name, path)
return ioutil.ReadFile(path)
}
@ -56,7 +56,7 @@ func (s *Store) Set(ctx context.Context, name string, value []byte) error {
return err
}
}
debug.Log("fs.Set(%s) - %s", name, filepath.Join(s.path, name))
debug.Log("Writing %s to %s", name, filepath.Join(s.path, name))
return ioutil.WriteFile(filepath.Join(s.path, name), value, 0644)
}
@ -66,7 +66,7 @@ func (s *Store) Delete(ctx context.Context, name string) error {
name = filepath.FromSlash(name)
}
path := filepath.Join(s.path, filepath.Clean(name))
debug.Log("fs.Delete(%s) - %s", name, path)
debug.Log("Deleting %s from %s", name, path)
if err := os.Remove(path); err != nil {
return err
@ -106,7 +106,7 @@ func (s *Store) Exists(ctx context.Context, name string) bool {
name = filepath.FromSlash(name)
}
path := filepath.Join(s.path, filepath.Clean(name))
debug.Log("fs.Exists(%s) - %s", name, path)
debug.Log("%s exists at %s", name, path)
return fsutil.IsFile(path)
}
@ -115,7 +115,7 @@ func (s *Store) Exists(ctx context.Context, name string) bool {
// directory separator are normalized using `/`
func (s *Store) List(ctx context.Context, prefix string) ([]string, error) {
prefix = strings.TrimPrefix(prefix, "/")
debug.Log("fs.List(%s)", prefix)
debug.Log("Listing %s", prefix)
files := make([]string, 0, 100)
if err := filepath.Walk(s.path, func(path string, info os.FileInfo, err error) error {
if err != nil {
@ -153,14 +153,14 @@ func (s *Store) IsDir(ctx context.Context, name string) bool {
}
path := filepath.Join(s.path, filepath.Clean(name))
isDir := fsutil.IsDir(path)
debug.Log("fs.Isdir(%s) - %s -> %t", name, path, isDir)
debug.Log("%s at %s is a directory? %t", name, path, isDir)
return isDir
}
// Prune removes a named directory
func (s *Store) Prune(ctx context.Context, prefix string) error {
path := filepath.Join(s.path, filepath.Clean(prefix))
debug.Log("fs.Prune(%s) - %s", prefix, path)
debug.Log("Purning %s from %s", prefix, path)
return os.RemoveAll(path)
}

View File

@ -20,10 +20,6 @@ import (
func (o *OnDisk) Fsck(ctx context.Context) error {
pcb := ctxutil.GetProgressCallback(ctx)
if err := o.Compact(); err != nil {
return err
}
// build a list of existing files
files := make(map[string]struct{}, len(o.idx.Entries)+1)
files[idxFile] = struct{}{}

View File

@ -82,7 +82,7 @@ func (o *OnDisk) Get(ctx context.Context, name string) ([]byte, error) {
return nil, fmt.Errorf("not found")
}
path := filepath.Join(o.dir, r.GetFilename())
debug.Log("Get(%s) - Reading from %s", name, path)
debug.Log("Reading %s from %s", name, path)
return ioutil.ReadFile(path)
}
@ -101,7 +101,7 @@ func (o *OnDisk) Set(ctx context.Context, name string, value []byte) error {
if err := ioutil.WriteFile(fp, value, 0600); err != nil {
return err
}
debug.Log("Set(%s) - Wrote to %s", name, fp)
debug.Log("Wrote %s to %s", name, fp)
e := o.getOrCreateEntry(name)
msg := "Updated " + fn
if cm := ctxutil.GetCommitMessage(ctx); cm != "" {
@ -114,7 +114,7 @@ func (o *OnDisk) Set(ctx context.Context, name string, value []byte) error {
Message: msg,
Filename: fn,
})
debug.Log("Set(%s) - Added Revision", name)
debug.Log("Added Revision for %s", name)
o.idx.Entries[name] = e
return o.saveIndex()
}
@ -135,7 +135,7 @@ func (o *OnDisk) getOrCreateEntry(name string) *gpb.Entry {
if e, found := o.idx.Entries[name]; found && e != nil {
return e
}
debug.Log("getEntry(%s) - Created new Entry", name)
debug.Log("Created new Entry for %s", name)
return &gpb.Entry{
Name: name,
Revisions: make([]*gpb.Revision, 0, 1),
@ -145,7 +145,7 @@ func (o *OnDisk) getOrCreateEntry(name string) *gpb.Entry {
// Delete removes an entry
func (o *OnDisk) Delete(ctx context.Context, name string) error {
if !o.Exists(ctx, name) {
debug.Log("Delete(%s) - Not adding tombstone for non-existing entry", name)
debug.Log("Not adding tombstone for non-existing entry for %s", name)
return nil
}
// add tombstone
@ -153,14 +153,14 @@ func (o *OnDisk) Delete(ctx context.Context, name string) error {
e.Delete(ctxutil.GetCommitMessage(ctx))
o.idx.Entries[name] = e
debug.Log("Delete(%s) - Added tombstone")
debug.Log("Added tombstone for %s")
return o.saveIndex()
}
// Exists checks if an entry exists
func (o *OnDisk) Exists(ctx context.Context, name string) bool {
_, found := o.idx.Entries[name]
debug.Log("Exists(%s): %t", name, found)
debug.Log("%s exists? %t", name, found)
return found
}
@ -216,7 +216,7 @@ func (o *OnDisk) Available(ctx context.Context) error {
// Compact will prune all deleted entries and truncate every other entry
// to the last 10 revisions.
func (o *OnDisk) Compact() error {
func (o *OnDisk) Compact(_ context.Context) error {
for k, v := range o.idx.Entries {
if v.IsDeleted() && time.Since(v.Latest().Time()) > delTTL {
delete(o.idx.Entries, k)

View File

@ -49,7 +49,7 @@ func loadConfig(l string) *Config {
func loadDefault() *Config {
cfg := New()
cfg.Path = PwStoreDir("")
debug.Log("config.Load(): %+v", cfg)
debug.Log("Loaded default config: %+v", cfg)
return cfg
}

View File

@ -85,7 +85,7 @@ func getRecipientInfo(ctx context.Context, crypto backend.Crypto, recipients []s
default:
}
kl, err := crypto.FindPublicKeys(ctx, r)
kl, err := crypto.FindRecipients(ctx, r)
if err != nil {
out.Error(ctx, "Failed to read public key for '%s': %s", r, err)
continue
@ -95,7 +95,7 @@ func getRecipientInfo(ctx context.Context, crypto backend.Crypto, recipients []s
name: "key not found",
}
if len(kl) > 0 {
ri.name = crypto.FormatKey(ctx, kl[0])
ri.name = crypto.FormatKey(ctx, kl[0], "")
}
ris = append(ris, ri)
}
@ -214,7 +214,7 @@ func AskForPrivateKey(ctx context.Context, crypto backend.Crypto, prompt string)
fmt.Fprintln(Stdout, prompt)
for i, k := range kl {
fmt.Fprintf(Stdout, "[%d] %s - %s\n", i, crypto.Name(), crypto.FormatKey(ctx, k))
fmt.Fprintf(Stdout, "[%d] %s - %s\n", i, crypto.Name(), crypto.FormatKey(ctx, k, ""))
}
iv, err := termio.AskForInt(ctx, fmt.Sprintf("Please enter the number of a key (0-%d, [q]uit)", len(kl)-1), 0)
if err != nil {
@ -256,8 +256,8 @@ func AskForGitConfigUser(ctx context.Context, crypto backend.Crypto) (string, st
default:
}
name := crypto.NameFromKey(ctx, key)
email := crypto.EmailFromKey(ctx, key)
name := crypto.FormatKey(ctx, key, "{{ .Identity.Name }}")
email := crypto.FormatKey(ctx, key, "{{ .Identity.Email }}")
if name == "" && email == "" {
continue

View File

@ -69,7 +69,7 @@ func Invoke(ctx context.Context, editor string, content []byte) ([]byte, error)
cmd.Stderr = Stderr
if err := cmd.Run(); err != nil {
debug.Log("editor - cmd: %s %+v - error: %+v", cmd.Path, cmd.Args, err)
debug.Log("cmd: %s %+v - error: %+v", cmd.Path, cmd.Args, err)
return []byte{}, errors.Errorf("failed to run %s with %s file: %s", editor, tmpfile.Name(), err)
}

View File

@ -15,13 +15,18 @@ import (
// Fsck checks all entries matching the given prefix
func (s *Store) Fsck(ctx context.Context, path string) error {
ctx = out.AddPrefix(ctx, "["+s.alias+"] ")
debug.Log("Fsck(%s)", path)
debug.Log("Checking %s", path)
// first let the storage backend check itself
if err := s.storage.Fsck(ctx); err != nil {
return errors.Wrapf(err, "storage backend found errors: %s", err)
}
// second give a chance to the RCS backend
if err := s.rcs.Compact(ctx); err != nil {
return errors.Wrapf(err, "rcs backend compaction failed: %s", err)
}
pcb := ctxutil.GetProgressCallback(ctx)
// then we'll make sure all the secrets are readable by us and every
@ -36,12 +41,17 @@ func (s *Store) Fsck(ctx context.Context, path string) error {
if strings.HasPrefix(name, s.alias+"/") {
name = strings.TrimPrefix(name, s.alias+"/")
}
debug.Log("sub.Fsck(%s) - Checking %s", path, name)
ctx := ctxutil.WithNoNetwork(ctx, true)
debug.Log("[%s] Checking %s", path, name)
if err := s.fsckCheckEntry(ctx, name); err != nil {
return errors.Wrapf(err, "failed to check %s: %s", name, err)
}
}
if err := s.rcs.Push(ctx, "", ""); err != nil {
out.Red(ctx, "RCS Push failed: %s", err)
}
return nil
}

View File

@ -31,7 +31,7 @@ func (s *Store) ImportMissingPublicKeys(ctx context.Context) error {
// we could list all keys outside the loop and just do the lookup here
// but this way we ensure to use the exact same lookup logic as
// gpg does on encryption
kl, err := s.crypto.FindPublicKeys(ctx, r)
kl, err := s.crypto.FindRecipients(ctx, r)
if err != nil {
out.Error(ctx, "[%s] Failed to get public key for %s: %s", s.alias, r, err)
}

View File

@ -31,7 +31,7 @@ You can add secondary stores with gopass init --path <path to secondary store> -
if id == "" {
continue
}
kl, err := s.crypto.FindPublicKeys(ctx, id)
kl, err := s.crypto.FindRecipients(ctx, id)
if err != nil {
out.Error(ctx, "Failed to fetch public key for '%s': %s", id, err)
continue
@ -47,7 +47,7 @@ You can add secondary stores with gopass init --path <path to secondary store> -
return errors.Errorf("failed to initialize store: no valid recipients given in %+v", ids)
}
kl, err := s.crypto.FindPrivateKeys(ctx, recipients...)
kl, err := s.crypto.FindIdentities(ctx, recipients...)
if err != nil {
return errors.Errorf("Failed to get available private keys: %s", err)
}

View File

@ -21,7 +21,7 @@ func (s *Store) List(ctx context.Context, prefix string) ([]string, error) {
if err != nil {
return nil, err
}
debug.Log("sub.List(%s): %+v\n", prefix, lst)
debug.Log("Listing %s: %+v\n", prefix, lst)
out := make([]string, 0, len(lst))
cExt := "." + s.crypto.Ext()
for _, path := range lst {

View File

@ -88,9 +88,9 @@ func (s *Store) delete(ctx context.Context, name string, recurse bool) error {
if err := s.rcs.Commit(ctx, fmt.Sprintf("Remove %s from store.", name)); err != nil {
switch errors.Cause(err) {
case store.ErrGitNotInit:
debug.Log("move - skipping git commit - git not initialized")
debug.Log("skipping git commit - git not initialized")
case store.ErrGitNothingToCommit:
debug.Log("move - skipping git commit - nothing to commit")
debug.Log("skipping git commit - nothing to commit")
default:
return errors.Wrapf(err, "failed to commit changes to git")
}

View File

@ -70,7 +70,7 @@ func (s *Store) SetRecipients(ctx context.Context, rs []string) error {
// but if this key is not available on this machine we
// just try to remove it literally
func (s *Store) RemoveRecipient(ctx context.Context, id string) error {
keys, err := s.crypto.FindPublicKeys(ctx, id)
keys, err := s.crypto.FindRecipients(ctx, id)
if err != nil {
out.Cyan(ctx, "Warning: Failed to get GPG Key Info for %s: %s", id, err)
}
@ -125,7 +125,7 @@ func (s *Store) ensureOurKeyID(ctx context.Context, rs []string) []string {
// (if any)
func (s *Store) OurKeyID(ctx context.Context) string {
for _, r := range s.Recipients(ctx) {
kl, err := s.crypto.FindPrivateKeys(ctx, r)
kl, err := s.crypto.FindIdentities(ctx, r)
if err != nil || len(kl) < 1 {
continue
}

View File

@ -98,22 +98,22 @@ func (s *Store) reencrypt(ctx context.Context) error {
if err := s.rcs.Add(ctx, p); err != nil {
switch errors.Cause(err) {
case store.ErrGitNotInit:
debug.Log("reencrypt - skipping git add - git not initialized")
debug.Log("skipping git add - git not initialized")
continue
default:
return errors.Wrapf(err, "failed to add '%s' to git", p)
}
}
debug.Log("reencrypt - added %s to git", p)
debug.Log("added %s to git", p)
}
}
if err := s.rcs.Commit(ctx, ctxutil.GetCommitMessage(ctx)); err != nil {
switch errors.Cause(err) {
case store.ErrGitNotInit:
debug.Log("reencrypt - skipping git commit - git not initialized")
debug.Log("skipping git commit - git not initialized")
case store.ErrGitNothingToCommit:
debug.Log("reencrypt - skipping git commit - nothing to commit")
debug.Log("skipping git commit - nothing to commit")
default:
return errors.Wrapf(err, "failed to commit changes to git")
}

View File

@ -23,7 +23,7 @@ type Store struct {
// Init initialized this sub store
func Init(ctx context.Context, alias, path string) (*Store, error) {
debug.Log("sub.Init(%s, %s) ...", alias, path)
debug.Log("Initializing %s at %s", alias, path)
s := &Store{
alias: alias,
path: path,
@ -52,7 +52,7 @@ func Init(ctx context.Context, alias, path string) (*Store, error) {
// New creates a new store
func New(ctx context.Context, alias, path string) (*Store, error) {
debug.Log("sub.New(%s, %s)", alias, path)
debug.Log("Instantiating %s at %s", alias, path)
s := &Store{
alias: alias,
@ -72,7 +72,7 @@ func New(ctx context.Context, alias, path string) (*Store, error) {
return nil, errors.Wrapf(err, "failed to init crypto backend: %s", err)
}
debug.Log("sub.New(%s, %s) - initialized - storage: %+#v - rcs: %+#v - crypto: %+#v", alias, path, s.storage, s.rcs, s.crypto)
debug.Log("Instantiated %s at %s - storage: %+#v - rcs: %+#v - crypto: %+#v", alias, path, s.storage, s.rcs, s.crypto)
return s, nil
}
@ -130,7 +130,7 @@ func (s *Store) useableKeys(ctx context.Context, name string) ([]string, error)
return rs, nil
}
kl, err := s.crypto.FindPublicKeys(ctx, rs...)
kl, err := s.crypto.FindRecipients(ctx, rs...)
if err != nil {
return rs, err
}

View File

@ -21,7 +21,7 @@ func (s *Store) Fsck(ctx context.Context, path string) error {
continue
}
path = strings.TrimPrefix(path, alias+"/")
debug.Log("root.Fsck() - Checking %s", alias)
debug.Log("Checking %s", alias)
if err := sub.Fsck(ctx, path); err != nil {
out.Error(ctx, "fsck failed on sub store %s: %s", alias, err)
result = multierror.Append(result, err)

View File

@ -45,7 +45,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error {
if err := subFrom.RCS().Commit(ctxFrom, fmt.Sprintf("Move from %s to %s", from, to)); delete && err != nil {
switch errors.Cause(err) {
case store.ErrGitNotInit:
debug.Log("reencrypt - skipping git commit - git not initialized")
debug.Log("skipping git commit - git not initialized")
default:
return errors.Wrapf(err, "failed to commit changes to git (from)")
}
@ -54,7 +54,7 @@ func (r *Store) move(ctx context.Context, from, to string, delete bool) error {
if err := subTo.RCS().Commit(ctxTo, fmt.Sprintf("Move from %s to %s", from, to)); err != nil {
switch errors.Cause(err) {
case store.ErrGitNotInit:
debug.Log("reencrypt - skipping git commit - git not initialized")
debug.Log("skipping git commit - git not initialized")
default:
return errors.Wrapf(err, "failed to commit changes to git (to)")
}

View File

@ -36,11 +36,11 @@ func (r *Store) RemoveRecipient(ctx context.Context, store, rec string) error {
func (r *Store) addRecipient(ctx context.Context, prefix string, root *tree.Root, recp string, pretty bool) error {
ctx, sub, _ := r.getStore(ctx, prefix)
key := fmt.Sprintf("%s (missing public key)", recp)
kl, err := sub.Crypto().FindPublicKeys(ctx, recp)
kl, err := sub.Crypto().FindRecipients(ctx, recp)
if err == nil {
if len(kl) > 0 {
if pretty {
key = sub.Crypto().FormatKey(ctx, kl[0])
key = sub.Crypto().FormatKey(ctx, kl[0], "")
} else {
key = kl[0]
}

View File

@ -39,12 +39,12 @@ func (s *Secret) decodeKV() error {
}
if mayBeYAML {
docSep, err := s.decodeYAML()
debug.Log("decodeKV() - mayBeYAML - err: %s", err)
debug.Log("Content my be YAML, but decoding failed: %s", err)
if docSep && err == nil && s.data != nil {
return nil
}
}
debug.Log("decodeKV() - simple KV")
debug.Log("Content is simple KV (no valid YAML)")
s.data = data
return nil
}
@ -76,11 +76,11 @@ func (s *Secret) encodeKV() error {
}
if mayBeYAML {
if err := s.encodeYAML(); err == nil {
debug.Log("encodeKV() - mayBeYAML - OK")
debug.Log("Content may be YAML. Successfully encoded")
return nil
}
}
debug.Log("encodeKV() - simple KV")
debug.Log("Content is no valid YAML. Encoded as simple KV")
s.body = buf.String()
return nil
}

View File

@ -0,0 +1,49 @@
package termio
import (
"context"
"os"
"github.com/gopasspw/gopass/pkg/ctxutil"
"github.com/urfave/cli/v2"
)
// DetectName tries to guess the name of the logged in user
func DetectName(ctx context.Context, c *cli.Context) string {
cand := make([]string, 0, 5)
cand = append(cand, ctxutil.GetUsername(ctx))
if c != nil {
cand = append(cand, c.String("name"))
}
cand = append(cand,
os.Getenv("GIT_AUTHOR_NAME"),
os.Getenv("DEBFULLNAME"),
os.Getenv("USER"),
)
for _, e := range cand {
if e != "" {
return e
}
}
return ""
}
// DetectEmail tries to guess the email of the logged in user
func DetectEmail(ctx context.Context, c *cli.Context) string {
cand := make([]string, 0, 5)
cand = append(cand, ctxutil.GetEmail(ctx))
if c != nil {
cand = append(cand, c.String("email"))
}
cand = append(cand,
os.Getenv("GIT_AUTHOR_EMAIL"),
os.Getenv("DEBEMAIL"),
os.Getenv("EMAIL"),
)
for _, e := range cand {
if e != "" {
return e
}
}
return ""
}

View File

@ -80,7 +80,7 @@ func IsUpdateable(ctx context.Context) error {
if err != nil {
return err
}
debug.Log("isUpdateable - File: %s", fn)
debug.Log("File: %s", fn)
// check if this is a test binary
if strings.HasSuffix(filepath.Base(fn), ".test") {
return nil