Implement loading passwords from external commands

* Resolves #80
This commit is contained in:
Galen Abell 2019-05-18 15:29:26 -04:00 committed by Drew DeVault
parent 98da4c9509
commit b8208509f4
4 changed files with 94 additions and 8 deletions

View file

@ -3,7 +3,9 @@ package config
import (
"errors"
"fmt"
"net/url"
"os"
"os/exec"
"path"
"regexp"
"strings"
@ -29,14 +31,16 @@ const (
)
type AccountConfig struct {
CopyTo string
Default string
From string
Name string
Source string
Folders []string
Params map[string]string
Outgoing string
CopyTo string
Default string
From string
Name string
Source string
SourceCredCmd string
Folders []string
Params map[string]string
Outgoing string
OutgoingCredCmd string
}
type BindingConfig struct {
@ -115,8 +119,12 @@ func loadAccountConfig(path string) ([]AccountConfig, error) {
for key, val := range sec.KeysHash() {
if key == "folders" {
account.Folders = strings.Split(val, ",")
} else if key == "source_cred_cmd" {
account.SourceCredCmd = val
} else if key == "outgoing" {
account.Outgoing = val
} else if key == "outgoing_cred_cmd" {
account.OutgoingCredCmd = val
} else if key == "from" {
account.From = val
} else if key == "copy-to" {
@ -128,6 +136,19 @@ func loadAccountConfig(path string) ([]AccountConfig, error) {
if account.Source == "" {
return nil, fmt.Errorf("Expected source for account %s", _sec)
}
source, err := parseCredential(account.Source, account.SourceCredCmd)
if err != nil {
return nil, fmt.Errorf("Invalid source credentials for %s: %s", _sec, err)
}
account.Source = source
outgoing, err := parseCredential(account.Outgoing, account.OutgoingCredCmd)
if err != nil {
return nil, fmt.Errorf("Invalid outgoing credentials for %s: %s", _sec, err)
}
account.Outgoing = outgoing
accounts = append(accounts, account)
}
if len(accounts) == 0 {
@ -137,6 +158,38 @@ func loadAccountConfig(path string) ([]AccountConfig, error) {
return accounts, nil
}
func parseCredential(cred, command string) (string, error) {
if cred == "" || command == "" {
return cred, nil
}
u, err := url.Parse(cred)
if err != nil {
return "", err
}
// ignore the command if a password is specified
if _, exists := u.User.Password(); exists {
return cred, nil
}
// don't attempt to parse the command if the url is a path (ie /usr/bin/sendmail)
if !u.IsAbs() {
return cred, nil
}
cmd := exec.Command("sh", "-c", command)
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("failed to read password: %s", err)
}
pw := strings.TrimSpace(string(output))
u.User = url.UserPassword(u.User.Username(), pw)
return u.String(), nil
}
func LoadConfig(root *string) (*AercConfig, error) {
if root == nil {
_root := path.Join(xdg.ConfigHome(), "aerc")

View file

@ -144,6 +144,12 @@ Note that many of these configuration options are written for you, such as
- *aerc-smtp*(5)
*outgoing_cred_cmd*
Specifies an optional command that is run to get the outgoing account's
password. See each protocol's man page for more details:
- *aerc-smtp*(5)
*source*
Specifies the source for reading incoming emails on this account. This key
is required for all accounts. It should be a connection string, and the
@ -154,6 +160,13 @@ Note that many of these configuration options are written for you, such as
Default: none
*source_cred_cmd*
Specifies an optional command that is run to get the source account's
password. See each protocol's man page for more details:
- *aerc-imap*(5)
# BINDS.CONF
This file is used for configuring keybindings used in the aerc interactive

View file

@ -35,6 +35,16 @@ available:
*imaps*:
IMAP with TLS/SSL
*source_cred_cmd*
Specifies the command to run to get the password for the IMAP
account. This command will be run using `sh -c [command]`. If a
password is specified in the *source* option, the password will
take precedence over this command.
Example:
`pass hostname/username`
# SEE ALSO
*aerc*(1) *aerc-config*(5) *aerc-smtp*(5)

View file

@ -39,6 +39,16 @@ available:
Authenticate with a username and password using AUTH PLAIN. This is the
default behavior.
*outgoing_cred_cmd*
Specifies the command to run to get the password for the SMTP
account. This command will be run using `sh -c [command]`. If a
password is specified in the *outgoing* option, the password will
take precedence over this command.
Example:
`pass hostname/username`
# SEE ALSO
*aerc*(1) *aerc-config*(5) *aerc-smtp*(5)