aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGalen Abell <galen@galenabell.com>2019-05-18 15:29:26 -0400
committerDrew DeVault <sir@cmpwn.com>2019-05-18 15:31:38 -0400
commitb8208509f47301bcb03bc222f5e5765833478250 (patch)
treeba089c1f60d05bf6ea48c027dc09a25467b1b765
parent98da4c9509d03f8ffe48b9c66b9c3ce8a0f2f942 (diff)
Implement loading passwords from external commands
* Resolves #80
-rw-r--r--config/config.go69
-rw-r--r--doc/aerc-config.5.scd13
-rw-r--r--doc/aerc-imap.5.scd10
-rw-r--r--doc/aerc-smtp.5.scd10
4 files changed, 94 insertions, 8 deletions
diff --git a/config/config.go b/config/config.go
index aef796c..d864d2c 100644
--- a/config/config.go
+++ b/config/config.go
@@ -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")
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index a221723..ecf7720 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -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
diff --git a/doc/aerc-imap.5.scd b/doc/aerc-imap.5.scd
index 5899a34..d676c7c 100644
--- a/doc/aerc-imap.5.scd
+++ b/doc/aerc-imap.5.scd
@@ -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)
diff --git a/doc/aerc-smtp.5.scd b/doc/aerc-smtp.5.scd
index 7d07125..17eb627 100644
--- a/doc/aerc-smtp.5.scd
+++ b/doc/aerc-smtp.5.scd
@@ -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)