Files
Dominik SchulzandYolan Romailler dfb8fcb787 Add .gitconfig parser
This commit adds yet another config handler for gopass. It is based on
the format used by git itself. This has the potential to address a lot
of long standing issues, but it also causes a lot of changes to how we
handle configuration, so bugs are inevitable.

Fixes #1567
Fixes #1764
Fixes #1819
Fixes #1878
Fixes #2387

RELEASE_NOTES=[BREAKING] New config format based on git config.

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
Co-authored-by: Yolan Romailler <AnomalRoil@users.noreply.github.com>
2022-11-12 21:15:52 +01:00

453 lines
13 KiB
Go

package ctxutil
import (
"context"
"fmt"
"time"
"github.com/gopasspw/gopass/internal/store"
"github.com/urfave/cli/v2"
)
type contextKey int
const (
ctxKeyTerminal contextKey = iota
ctxKeyInteractive
ctxKeyStdin
ctxKeyGitCommit
ctxKeyAlwaysYes
ctxKeyVerbose
ctxKeyProgressCallback
ctxKeyAlias
ctxKeyGitInit
ctxKeyForce
ctxKeyCommitMessage
ctxKeyNoNetwork
ctxKeyUsername
ctxKeyEmail
ctxKeyImportFunc
ctxKeyPasswordCallback
ctxKeyPasswordPurgeCallback
ctxKeyCommitTimestamp
ctxKeyShowParsing
ctxKeyHidden
)
// ErrNoCallback is returned when no callback is set in the context.
var ErrNoCallback = fmt.Errorf("no callback")
// WithGlobalFlags parses any global flags from the cli context and returns
// a regular context.
func WithGlobalFlags(c *cli.Context) context.Context {
if c.Bool("yes") {
return WithAlwaysYes(c.Context, true)
}
return c.Context
}
// ProgressCallback is a callback for updateing progress.
type ProgressCallback func()
// WithTerminal returns a context with an explicit value for terminal.
func WithTerminal(ctx context.Context, isTerm bool) context.Context {
return context.WithValue(ctx, ctxKeyTerminal, isTerm)
}
// HasTerminal returns true if a value for Terminal has been set in this context.
func HasTerminal(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyTerminal).(bool)
return ok
}
// IsTerminal returns the value of terminal or the default (true).
func IsTerminal(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyTerminal).(bool)
if !ok {
return true
}
return bv
}
// WithInteractive returns a context with an explicit value for interactive.
func WithInteractive(ctx context.Context, isInteractive bool) context.Context {
return context.WithValue(ctx, ctxKeyInteractive, isInteractive)
}
// HasInteractive returns true if a value for Interactive has been set in this context.
func HasInteractive(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyInteractive).(bool)
return ok
}
// IsInteractive returns the value of interactive or the default (true).
func IsInteractive(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyInteractive).(bool)
if !ok {
return true
}
return bv
}
// WithStdin returns a context with the value for Stdin set. If true some input
// is available on Stdin (e.g. something is being piped into it).
func WithStdin(ctx context.Context, isStdin bool) context.Context {
return context.WithValue(ctx, ctxKeyStdin, isStdin)
}
// HasStdin returns true if a value for Stdin has been set in this context.
func HasStdin(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyStdin).(bool)
return ok
}
// IsStdin returns the value of stdin, i.e. if it's true some data is being
// piped to stdin. If not set it returns the default value (false).
func IsStdin(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyStdin).(bool)
if !ok {
return false
}
return bv
}
// WithShowParsing returns a context with the value for ShowParsing set.
func WithShowParsing(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyShowParsing, bv)
}
// HasShowParsing returns true if a value for ShowParsing has been set in this context.
func HasShowParsing(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyShowParsing).(bool)
return ok
}
// IsShowParsing returns the value of ShowParsing or the default (true).
func IsShowParsing(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyShowParsing).(bool)
if !ok {
return true
}
return bv
}
// WithGitCommit returns a context with the value of git commit set.
func WithGitCommit(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyGitCommit, bv)
}
// HasGitCommit returns true if a value for GitCommit has been set in this context.
func HasGitCommit(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyGitCommit).(bool)
return ok
}
// IsGitCommit returns the value of git commit or the default (true).
func IsGitCommit(ctx context.Context) bool {
return is(ctx, ctxKeyGitCommit, true)
}
// WithAlwaysYes returns a context with the value of always yes set.
func WithAlwaysYes(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyAlwaysYes, bv)
}
// HasAlwaysYes returns true if a value for AlwaysYes has been set in this context.
func HasAlwaysYes(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyAlwaysYes).(bool)
return ok
}
// IsAlwaysYes returns the value of always yes or the default (false).
func IsAlwaysYes(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyAlwaysYes).(bool)
if !ok {
return false
}
return bv
}
// WithVerbose returns a context with the value for verbose set.
func WithVerbose(ctx context.Context, verbose bool) context.Context {
return context.WithValue(ctx, ctxKeyVerbose, verbose)
}
// HasVerbose returns true if a value for Verbose has been set in this context.
func HasVerbose(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyVerbose).(bool)
return ok
}
// IsVerbose returns the value of verbose or the default (false).
func IsVerbose(ctx context.Context) bool {
return is(ctx, ctxKeyVerbose, false)
}
// WithProgressCallback returns a context with the value of ProgressCallback set.
func WithProgressCallback(ctx context.Context, cb ProgressCallback) context.Context {
return context.WithValue(ctx, ctxKeyProgressCallback, cb)
}
// HasProgressCallback returns true if a ProgressCallback has been set.
func HasProgressCallback(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyProgressCallback).(ProgressCallback)
return ok
}
// GetProgressCallback return the set progress callback or a default one.
// It never returns nil.
func GetProgressCallback(ctx context.Context) ProgressCallback {
cb, ok := ctx.Value(ctxKeyProgressCallback).(ProgressCallback)
if !ok || cb == nil {
return func() {}
}
return cb
}
// WithAlias returns an context with the alias set.
func WithAlias(ctx context.Context, alias string) context.Context {
return context.WithValue(ctx, ctxKeyAlias, alias)
}
// HasAlias returns true if a value for alias has been set.
func HasAlias(ctx context.Context) bool {
return hasString(ctx, ctxKeyAlias)
}
// GetAlias returns an alias if it has been set or an empty string otherwise.
func GetAlias(ctx context.Context) string {
a, ok := ctx.Value(ctxKeyAlias).(string)
if !ok {
return ""
}
return a
}
// WithGitInit returns a context with the value for the git init flag set.
func WithGitInit(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyGitInit, bv)
}
// HasGitInit returns true if the git init flag was set.
func HasGitInit(ctx context.Context) bool {
return hasBool(ctx, ctxKeyGitInit)
}
// IsGitInit returns the value of the git init flag or ture if none was set.
func IsGitInit(ctx context.Context) bool {
return is(ctx, ctxKeyGitInit, true)
}
// WithForce returns a context with the force flag set.
func WithForce(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyForce, bv)
}
// HasForce returns true if the context has the force flag set.
func HasForce(ctx context.Context) bool {
return hasBool(ctx, ctxKeyForce)
}
// IsForce returns the force flag value of the default (false).
func IsForce(ctx context.Context) bool {
return is(ctx, ctxKeyForce, false)
}
// WithCommitMessage returns a context with a commit message set.
func WithCommitMessage(ctx context.Context, sv string) context.Context {
return context.WithValue(ctx, ctxKeyCommitMessage, sv)
}
// HasCommitMessage returns true if the commit message was set.
func HasCommitMessage(ctx context.Context) bool {
return hasString(ctx, ctxKeyCommitMessage)
}
// GetCommitMessage returns the set commit message or an empty string.
func GetCommitMessage(ctx context.Context) string {
sv, ok := ctx.Value(ctxKeyCommitMessage).(string)
if !ok {
return ""
}
return sv
}
// WithNoNetwork returns a context with the value of no network set.
func WithNoNetwork(ctx context.Context, bv bool) context.Context {
return context.WithValue(ctx, ctxKeyNoNetwork, bv)
}
// HasNoNetwork returns true if no network was set.
func HasNoNetwork(ctx context.Context) bool {
return hasBool(ctx, ctxKeyNoNetwork)
}
// IsNoNetwork returns the value of no network or false.
func IsNoNetwork(ctx context.Context) bool {
return is(ctx, ctxKeyNoNetwork, false)
}
// WithUsername returns a context with the username set in the context.
func WithUsername(ctx context.Context, sv string) context.Context {
return context.WithValue(ctx, ctxKeyUsername, sv)
}
// GetUsername returns the username from the context.
func GetUsername(ctx context.Context) string {
sv, ok := ctx.Value(ctxKeyUsername).(string)
if !ok {
return ""
}
return sv
}
// WithEmail returns a context with the email set in the context.
func WithEmail(ctx context.Context, sv string) context.Context {
return context.WithValue(ctx, ctxKeyEmail, sv)
}
// GetEmail returns the email from the context.
func GetEmail(ctx context.Context) string {
sv, ok := ctx.Value(ctxKeyEmail).(string)
if !ok {
return ""
}
return sv
}
// WithImportFunc will return a context with the import callback set.
func WithImportFunc(ctx context.Context, imf store.ImportCallback) context.Context {
return context.WithValue(ctx, ctxKeyImportFunc, imf)
}
// HasImportFunc returns true if a value for import func has been set in this
// context.
func HasImportFunc(ctx context.Context) bool {
imf, ok := ctx.Value(ctxKeyImportFunc).(store.ImportCallback)
return ok && imf != nil
}
// GetImportFunc will return the import callback or a default one returning true
// Note: will never return nil.
func GetImportFunc(ctx context.Context) store.ImportCallback {
imf, ok := ctx.Value(ctxKeyImportFunc).(store.ImportCallback)
if !ok || imf == nil {
return func(context.Context, string, []string) bool {
return true
}
}
return imf
}
// PasswordCallback is a password prompt callback.
type PasswordCallback func(string, bool) ([]byte, error)
// WithPasswordCallback returns a context with the password callback set.
func WithPasswordCallback(ctx context.Context, cb PasswordCallback) context.Context {
return context.WithValue(ctx, ctxKeyPasswordCallback, cb)
}
// HasPasswordCallback returns true if a password callback was set in the context.
func HasPasswordCallback(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyPasswordCallback).(PasswordCallback)
return ok
}
// GetPasswordCallback returns the password callback or a default (which always fails).
func GetPasswordCallback(ctx context.Context) PasswordCallback {
pwcb, ok := ctx.Value(ctxKeyPasswordCallback).(PasswordCallback)
if !ok || pwcb == nil {
return func(string, bool) ([]byte, error) {
return nil, ErrNoCallback
}
}
return pwcb
}
// PasswordPurgeCallback is a callback to purge a password cached by PasswordCallback.
type PasswordPurgeCallback func(string)
// WithPasswordPurgeCallback returns a context with the password purge callback set.
func WithPasswordPurgeCallback(ctx context.Context, cb PasswordPurgeCallback) context.Context {
return context.WithValue(ctx, ctxKeyPasswordPurgeCallback, cb)
}
// HasPasswordPurgeCallback returns true if a password purge callback was set in the context.
func HasPasswordPurgeCallback(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyPasswordPurgeCallback).(PasswordPurgeCallback)
return ok
}
// GetPasswordPurgeCallback returns the password purge callback or a default (which is a no-op).
func GetPasswordPurgeCallback(ctx context.Context) PasswordPurgeCallback {
ppcb, ok := ctx.Value(ctxKeyPasswordPurgeCallback).(PasswordPurgeCallback)
if !ok || ppcb == nil {
return func(string) {}
}
return ppcb
}
// WithCommitTimestamp returns a context with the value for the commit
// timestamp set.
func WithCommitTimestamp(ctx context.Context, ts time.Time) context.Context {
return context.WithValue(ctx, ctxKeyCommitTimestamp, ts)
}
// HasCommitTimestamp returns true if the value for the commit timestamp
// was set in the context.
func HasCommitTimestamp(ctx context.Context) bool {
_, ok := ctx.Value(ctxKeyCommitTimestamp).(time.Time)
return ok
}
// GetCommitTimestamp returns the commit timestamp from the context if
// set or the default (now) otherwise.
func GetCommitTimestamp(ctx context.Context) time.Time {
if ts, ok := ctx.Value(ctxKeyCommitTimestamp).(time.Time); ok {
return ts
}
return time.Now()
}
// WithHidden returns a context with the flag value for hidden set.
func WithHidden(ctx context.Context, hidden bool) context.Context {
return context.WithValue(ctx, ctxKeyHidden, hidden)
}
// IsHidden returns true if any output should be hidden in this context.
func IsHidden(ctx context.Context) bool {
bv, ok := ctx.Value(ctxKeyHidden).(bool)
if !ok {
return false
}
return bv
}