diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pinentry/pinentry.go | 71 | ||||
-rw-r--r-- | lib/pinentry/ttyname.go | 45 | ||||
-rw-r--r-- | lib/ui/ui.go | 13 |
3 files changed, 129 insertions, 0 deletions
diff --git a/lib/pinentry/pinentry.go b/lib/pinentry/pinentry.go new file mode 100644 index 00000000..51b54920 --- /dev/null +++ b/lib/pinentry/pinentry.go @@ -0,0 +1,71 @@ +package pinentry + +import ( + "fmt" + "os" + "os/exec" + "strings" + "sync/atomic" + + "git.sr.ht/~rjarry/aerc/config" + "git.sr.ht/~rjarry/aerc/lib/log" + "git.sr.ht/~rjarry/aerc/lib/ui" +) + +var pinentryMode int32 = 0 + +func Enable() { + if !config.General.UsePinentry { + return + } + if atomic.SwapInt32(&pinentryMode, 1) == 1 { + // cannot enter pinentry mode twice + return + } + ui.SuspendScreen() +} + +func Disable() { + if atomic.SwapInt32(&pinentryMode, 0) == 0 { + // not in pinentry mode + return + } + ui.ResumeScreen() +} + +func SetCmdEnv(cmd *exec.Cmd) { + if cmd == nil || atomic.LoadInt32(&pinentryMode) == 0 { + return + } + + env := cmd.Env + if env == nil { + env = os.Environ() + } + + hasTerm := false + hasGPGTTY := false + for _, e := range env { + switch { + case strings.HasPrefix(strings.ToUpper(e), "TERM="): + log.Debugf("pinentry: use %v", e) + hasTerm = true + case strings.HasPrefix(strings.ToUpper(e), "GPG_TTY="): + log.Debugf("pinentry: use %v", e) + hasGPGTTY = true + } + } + + if !hasTerm { + env = append(env, "TERM=xterm-256color") + log.Debugf("pinentry: set TERM=xterm-256color") + } + + if !hasGPGTTY { + tty := ttyname() + env = append(env, fmt.Sprintf("GPG_TTY=%s", tty)) + log.Debugf("pinentry: set GPG_TTY=%s", tty) + } + + cmd.Env = env +} diff --git a/lib/pinentry/ttyname.go b/lib/pinentry/ttyname.go new file mode 100644 index 00000000..053cff74 --- /dev/null +++ b/lib/pinentry/ttyname.go @@ -0,0 +1,45 @@ +package pinentry + +import ( + "fmt" + "os" + "strings" + + "git.sr.ht/~rjarry/aerc/lib/log" +) + +var missingGPGTTYmsg = ` +You need to set GPG_TTY manually before starting aerc. Add the following to your +.bashrc or whatever initialization file is used for shell invocations: + + GPG_TTY=$(tty) + export GPG_TTY + +Further information can be found here: +https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html +` + +// ttyname returns current name of the pty. This is necessary in order to tell +// pinentry where to ask for the passphrase. +// +// If there is a GPG_TTY environment variable set, use this one. Otherwise, try +// readline() on /proc/<pid>/fd/0. +// +// If both approaches fail, the user's only option is to set GPG_TTY manually. +// +// If tty name could not be determined, an empty string is returned. +func ttyname() string { + if s := os.Getenv("GPG_TTY"); s != "" { + return s + } + + // try readlink or else show missing GPG_TTY warning msg + tty, err := os.Readlink(fmt.Sprintf("/proc/%d/fd/0", os.Getpid())) + if err != nil { + log.Debugf("readlink: '%s' with err: %v", tty, err) + log.Warnf(missingGPGTTYmsg) + return "" + } + + return strings.TrimSpace(tty) +} diff --git a/lib/ui/ui.go b/lib/ui/ui.go index c20eac37..3680fb1a 100644 --- a/lib/ui/ui.go +++ b/lib/ui/ui.go @@ -99,6 +99,19 @@ func QueueSuspend() { } } +// SuspendScreen should be called from the main thread. +func SuspendScreen() { + _ = state.vx.Suspend() +} + +func ResumeScreen() { + err := state.vx.Resume() + if err != nil { + log.Errorf("ui: cannot resume after suspend: %v", err) + } + Invalidate() +} + func Suspend() error { var err error if atomic.SwapUint32(&state.suspending, 0) != 0 { |