mirror of
https://github.com/gopasspw/gopass.git
synced 2025-12-08 19:24:54 +00:00
Cleanup interfaces (#1401)
RELEASE_NOTES=n/a Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
This commit is contained in:
parent
d7db829fad
commit
e623b38665
1
go.mod
1
go.mod
@ -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
2
go.sum
@ -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=
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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, "")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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...)
|
||||
}
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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"))
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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{}{}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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{}{}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)")
|
||||
}
|
||||
|
||||
@ -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]
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
49
internal/termio/identity.go
Normal file
49
internal/termio/identity.go
Normal 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 ""
|
||||
}
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user