diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c2460e890..03def4393a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,3 +62,4 @@ If any of the above don't work check out the [troubleshooting section](#troubles ## Releasing See [docs/releases.md](docs/releases.md). + diff --git a/docs/hacking.md b/docs/hacking.md new file mode 100644 index 0000000000..338d31d974 --- /dev/null +++ b/docs/hacking.md @@ -0,0 +1,39 @@ +# Hacking on gopass + +Note: See [CONTRIBUTING.md](../CONTRIBUTING.md) for an overview. + +This document provides an overview on how to develop on gopass. + +## Setting up an isolated development environment + +### With GPG + +`gopass` should fully respect `GOPASS_HOMEDIR` overriding all gopass internal paths. +However it will still use your normal GPG keyring and configuration. To override this +you will need to set `GNUPGHOME` as well and possibly generate a new keyring. + +```bash +$ export GOPASS_DEBUG_LOG=/tmp/gp1.log +$ export GOPASS_HOMEDIR=/tmp/gp1 +$ mkdir -p $GOPASS_HOMEDIR +$ export GNUPGHOME=$GOPASS_HOMEDIR/.gnupg +# Make sure that you're using the correct keyring. +$ gpg -K +gpg: directory '/tmp/gp1/.gnupg' created +gpg: keybox '/tmp/gp1/.gnupg/pubring.kbx' created +gpg: /tmp/gp1/.gnupg/trustdb.gpg: trustdb created +$ gpg --gen-key +$ go build && ./gopass setup --crypto gpg --storage gitfs +``` + +### With age + +Using `age` is recommended for development since it's easier to set up. Setting +`GOPASS_HOMEDIR` should be sufficient to ensure an isolated environment. + +```bash +$ export GOPASS_DEBUG_LOG=/tmp/gp1.log +$ export GOPASS_HOMEDIR=/tmp/gp1 +$ mkdir -p $GOPASS_HOMEDIR +$ go build && ./gopass setup --crypto age --storage gitfs +``` diff --git a/internal/action/clone.go b/internal/action/clone.go index 161e38e716..836b993b0a 100644 --- a/internal/action/clone.go +++ b/internal/action/clone.go @@ -120,7 +120,7 @@ func (s *Action) clone(ctx context.Context, repo, mount, path string) error { // make sure the parent directory exists. if parentPath := filepath.Dir(path); !fsutil.IsDir(parentPath) { - if err := os.MkdirAll(parentPath, 0700); err != nil { + if err := os.MkdirAll(parentPath, 0o700); err != nil { return exit.Error(exit.Unknown, err, "Failed to create parent directory for clone: %s", err) } } @@ -200,7 +200,21 @@ func (s *Action) cloneCheckDecryptionKeys(ctx context.Context, mount string) err return nil } + var exported bool + if sub, err := s.Store.GetSubStore(mount); err == nil { + debug.Log("exporting public keys: %v", idSet.Elements()) + exported, err = sub.ExportMissingPublicKeys(ctx, idSet.Elements()) + if err != nil { + debug.Log("failed to export missing public keys: %w", err) + } + } else { + debug.Log("failed to get sub store: %s", err) + } + out.Noticef(ctx, "Please ask the owner of the password store to add one of your keys: %s", strings.Join(idSet.Elements(), ", ")) + if exported { + out.Noticef(ctx, "The missing keys were exported to the password store. Run `gopass sync` to push them.") + } return nil } diff --git a/internal/action/recipients.go b/internal/action/recipients.go index 155f34a64c..f8ee07796c 100644 --- a/internal/action/recipients.go +++ b/internal/action/recipients.go @@ -14,8 +14,7 @@ import ( "github.com/urfave/cli/v2" ) -var ( - removalWarning = ` +var removalWarning = ` @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -31,7 +30,6 @@ This feature is only meant for revoking access to any added or changed credentials. ` -) // RecipientsPrint prints all recipients per store. func (s *Action) RecipientsPrint(c *cli.Context) error { @@ -95,8 +93,15 @@ func (s *Action) RecipientsAdd(c *cli.Context) error { for _, r := range recipients { keys, err := crypto.FindRecipients(ctx, r) if err != nil { - out.Printf(ctx, "WARNING: Failed to list public key %q: %s", r, err) - if !force { + out.Warningf(ctx, "Failed to list public key %q: %s", r, err) + var imported bool + if sub, err := s.Store.GetSubStore(store); err == nil { + if err := sub.ImportMissingPublicKeys(ctx, r); err != nil { + out.Warningf(ctx, "Failed to import missing public keys: %s", err) + } + imported = err == nil + } + if !force && !imported { continue } keys = []string{r} diff --git a/internal/config/config.go b/internal/config/config.go index e23caf386c..0131f17bb1 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -37,7 +37,7 @@ type Config struct { // New creates a new config with sane default values. func New() *Config { return &Config{ - AutoImport: true, + AutoImport: false, ClipTimeout: 45, ExportKeys: true, Mounts: make(map[string]string), diff --git a/internal/config/config_test.go b/internal/config/config_test.go index b9170694bb..03ea745b6c 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -20,7 +20,7 @@ func TestNewConfig(t *testing.T) { cfg := config.New() cs := cfg.String() - assert.Contains(t, cs, `&config.Config{AutoClip:false, AutoImport:true, ClipTimeout:45, ExportKeys:true, NoPager:false, Notifications:true,`) + assert.Contains(t, cs, `&config.Config{AutoClip:false, AutoImport:false, ClipTimeout:45, ExportKeys:true, NoPager:false, Notifications:true,`) assert.Contains(t, cs, `SafeContent:false, Mounts:map[string]string{},`) cfg = &config.Config{ diff --git a/internal/store/leaf/crypto.go b/internal/store/leaf/crypto.go index 9201ac6dd8..6529968c32 100644 --- a/internal/store/leaf/crypto.go +++ b/internal/store/leaf/crypto.go @@ -28,7 +28,7 @@ func (s *Store) Crypto() backend.Crypto { // ImportMissingPublicKeys will try to import any missing public keys from the // .public-keys folder in the password store. -func (s *Store) ImportMissingPublicKeys(ctx context.Context) error { +func (s *Store) ImportMissingPublicKeys(ctx context.Context, newrs ...string) error { // do not import any keys for age, where public key == key id // TODO: do not hard code exceptions, ask the backend if it supports it if _, ok := s.crypto.(*age.Age); ok { @@ -39,6 +39,7 @@ func (s *Store) ImportMissingPublicKeys(ctx context.Context) error { if err != nil { return fmt.Errorf("failed to get recipients: %w", err) } + rs = append(rs, newrs...) for _, r := range rs { debug.Log("Checking recipients %s ...", r) // check if this recipient is missing