func (s *Action) initLocal(ctx context.Context) error {
	path := ""
	if s.Store != nil {
		path = s.Store.Path()
	}
	out.Printf(ctx, "🌟 Configuring your password store ...")
	if err := s.init(ctxutil.WithHidden(ctx, true), "", path); err != nil {
		return fmt.Errorf("failed to init local store: %w", err)
	}
	if want, err := termio.AskForBool(ctx, "❓ Do you want to add a git remote?", false); err == nil && want {
		out.Printf(ctx, "Configuring the git remote ...")
		if err := s.initSetupGitRemote(ctx, "", ""); err != nil {
			return fmt.Errorf("failed to setup git remote: %w", err)
		}
	}
	if err := s.cfg.Save(); err != nil {
		return fmt.Errorf("failed to save config: %w", err)
	}
	out.OK(ctx, "Configured")
	return nil
}
initLocal will initialize a local store, useful for local-only setups or as
part of team setups to create the root store
package action
import (
	"context"
	"fmt"
	"os"
	"github.com/fatih/color"
	"github.com/gopasspw/gopass/internal/backend"
	"github.com/gopasspw/gopass/internal/backend/crypto/gpg"
	"github.com/gopasspw/gopass/internal/out"
	"github.com/gopasspw/gopass/internal/store/root"
	"github.com/gopasspw/gopass/pkg/ctxutil"
	"github.com/gopasspw/gopass/pkg/debug"
	"github.com/gopasspw/gopass/pkg/pwgen/xkcdgen"
	"github.com/gopasspw/gopass/pkg/termio"
	"github.com/urfave/cli/v2"
)
func (s *Action) Setup(c *cli.Context) error {
	ctx := ctxutil.WithGlobalFlags(c)
	remote := c.String("remote")
	team := c.String("alias")
	create := c.Bool("create")
	ctx = initParseContext(ctx, c)
	out.Printf(ctx, logo)
	out.Printf(ctx, "🌟 Welcome to gopass!")
	out.Printf(ctx, "🌟 Initializing a new password store ...")
	if name := termio.DetectName(c.Context, c); name != "" {
		ctx = ctxutil.WithUsername(ctx, name)
	}
	if email := termio.DetectEmail(c.Context, c); email != "" {
		ctx = ctxutil.WithEmail(ctx, email)
	}
	s.Store = root.New(s.cfg)
	inited, err := s.Store.IsInitialized(ctx)
	if err != nil {
		return ExitError(ExitUnknown, err, "Failed to initialized store: %s", err)
	}
	if inited {
		out.Errorf(ctx, "Store is already initialized. Aborting.")
		return nil
	}
	debug.Log("Starting Onboarding Wizard - remote: %s - team: %s - create: %t - name: %s - email: %s", remote, team, create, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx))
	crypto := s.getCryptoFor(ctx, team)
	if crypto == nil {
		return fmt.Errorf("can not continue without crypto")
	}
	debug.Log("Crypto Backend initialized as: %s", crypto.Name())
	if !s.initHasUseablePrivateKeys(ctx, crypto) {
		out.Printf(ctx, "🔐 No useable cryptographic keys. Generating new key pair")
		out.Printf(ctx, "🕰 Key generation may take up to a few minutes")
		if err := s.initGenerateIdentity(ctx, crypto, ctxutil.GetUsername(ctx), ctxutil.GetEmail(ctx)); err != nil {
			return fmt.Errorf("failed to create new private key: %w", err)
		}
		out.Printf(ctx, "🔐 Cryptographic keys generated")
	}
	debug.Log("We have useable private keys")
	if remote != "" && team != "" {
		if create {
			return s.initCreateTeam(ctx, team, remote)
		}
		return s.initJoinTeam(ctx, team, remote)
	}
	return s.initLocal(ctx)
}
func (s *Action) initGenerateIdentity(ctx context.Context, crypto backend.Crypto, name, email string) error {
	out.Printf(ctx, "🧪 Creating cryptographic key pair (%s) ...", crypto.Name())
	out.Printf(ctx, "🎩 Gathering information for the key pair ...")
	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
	}
	passphrase := xkcdgen.Random()
	pwGenerated := true
	want, err := termio.AskForBool(ctx, "⚠ Do you want to enter a passphrase? (otherwise we generate one for you)", false)
	if err != nil {
		return err
	}
	if want {
		pwGenerated = false
		sv, err := termio.AskForPassword(ctx, "passphrase for your new keypair", true)
		if err != nil {
			return fmt.Errorf("failed to read passphrase: %w", err)
		}
		passphrase = sv
	}
	out.Printf(ctx, "⏳ This can take a long time. If you get impatient see https://github.com/gopasspw/gopass/blob/master/docs/entropy.md")
	if want, err := termio.AskForBool(ctx, "Continue?", true); err != nil || !want {
		return fmt.Errorf("user aborted: %w", err)
	}
	if err := crypto.GenerateIdentity(ctx, name, email, passphrase); err != nil {
		return fmt.Errorf("failed to create new private key: %w", err)
	}
	out.OKf(ctx, "Key pair generated")
	if pwGenerated {
		out.Printf(ctx, color.MagentaString("Passphrase: ")+passphrase)
		out.Noticef(ctx, "You need to remember this very well!")
	}
	kl, err := crypto.ListIdentities(gpg.WithUseCache(ctx, false))
	if err != nil {
		return fmt.Errorf("failed to list private keys: %w", err)
	}
	if len(kl) > 1 {
		out.Notice(ctx, "More than one private key detected. Make sure to use the correct one!")
		return nil
	}
	if len(kl) < 1 {
		return fmt.Errorf("failed to create a usable key pair")
	}
	if err := s.initExportPublicKey(ctx, crypto, kl[0]); err != nil {
		return err
	}
	out.OK(ctx, "Key pair validated")
	return nil
}
type keyExporter interface {
	ExportPublicKey(ctx context.Context, id string) ([]byte, error)
}
func (s *Action) initExportPublicKey(ctx context.Context, crypto backend.Crypto, key string) error {
	exp, ok := crypto.(keyExporter)
	if !ok {
		debug.Log("crypto backend %T can not export public keys", crypto)
		return nil
	}
	fn := key + ".pub.key"
	want, err := termio.AskForBool(ctx, fmt.Sprintf("Do you want to export your public key to %q?", fn), false)
	if err != nil {
		return err
	}
	if !want {
		return nil
	}
	pk, err := exp.ExportPublicKey(ctx, key)
	if err != nil {
		return fmt.Errorf("failed to export public key: %w", err)
	}
	if err := os.WriteFile(fn, pk, 06444); err != nil {
		out.Errorf(ctx, "❌ Failed to export public key %q: %q", fn, err)
		return err
	}
	out.Printf(ctx, "✴ Public key exported to %q", fn)
	return nil
}
func (s *Action) initHasUseablePrivateKeys(ctx context.Context, crypto backend.Crypto) bool {
	kl, err := crypto.ListIdentities(gpg.WithAlwaysTrust(ctx, false))
	if err != nil {
		return false
	}
	debug.Log("available private keys: %+v", kl)
	return len(kl) > 0
}
func (s *Action) initSetupGitRemote(ctx context.Context, team, remote string) error {
	var err error
	remote, err = termio.AskForString(ctx, "Please enter the git remote for your shared store", remote)
	if err != nil {
		return fmt.Errorf("failed to read user input: %w", err)
	}
	ctx = ctxutil.WithHidden(ctx, true)
	if err := s.Store.RCSAddRemote(ctx, team, "origin", remote); err != nil {
		return fmt.Errorf("failed to add git remote: %w", err)
	}
	if err := s.Store.RCSPull(ctx, team, "origin", "master"); err != nil {
		debug.Log("Initial git pull failed: %s", err)
	}
	if err := s.Store.RCSPush(ctx, team, "origin", "master"); err != nil {
		return fmt.Errorf("failed to push to git remote: %w", err)
	}
	return nil
}