aboutsummaryrefslogtreecommitdiffstats
path: root/config/config.go
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-11-14 11:45:16 +0100
committerRobin Jarry <robin@jarry.cc>2022-11-16 16:11:52 +0100
commit5402bfef76ed6d0cb9a89fc9d0ea6bda72dcc288 (patch)
tree185df3119638dd1850f1d243f9fb2edce3baec83 /config/config.go
parent5109f8369db9c55684b3be76809627172b4a11e1 (diff)
downloadaerc-5402bfef76ed6d0cb9a89fc9d0ea6bda72dcc288.tar.gz
config: move accounts.conf parsing in separate file
The config.go file is getting too big. Move accounts.conf parsing logic into a dedicated accounts.go file. No functional change. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Moritz Poldrack <moritz@poldrack.dev>
Diffstat (limited to 'config/config.go')
-rw-r--r--config/config.go251
1 files changed, 1 insertions, 250 deletions
diff --git a/config/config.go b/config/config.go
index 17c88834..6a16234b 100644
--- a/config/config.go
+++ b/config/config.go
@@ -4,13 +4,9 @@ import (
"errors"
"fmt"
"log"
- "net/url"
"os"
- "os/exec"
"path"
"regexp"
- "sort"
- "strconv"
"strings"
"time"
"unicode"
@@ -106,93 +102,6 @@ const (
FILTER_HEADER
)
-type RemoteConfig struct {
- Value string
- PasswordCmd string
- CacheCmd bool
- cache string
-}
-
-func (c *RemoteConfig) parseValue() (*url.URL, error) {
- return url.Parse(c.Value)
-}
-
-func (c *RemoteConfig) ConnectionString() (string, error) {
- if c.Value == "" || c.PasswordCmd == "" {
- return c.Value, nil
- }
-
- u, err := c.parseValue()
- if err != nil {
- return "", err
- }
-
- // ignore the command if a password is specified
- if _, exists := u.User.Password(); exists {
- return c.Value, nil
- }
-
- // don't attempt to parse the command if the url is a path (ie /usr/bin/sendmail)
- if !u.IsAbs() {
- return c.Value, nil
- }
-
- pw := c.cache
-
- if pw == "" {
- cmd := exec.Command("sh", "-c", c.PasswordCmd)
- cmd.Stdin = os.Stdin
- output, err := cmd.Output()
- if err != nil {
- return "", fmt.Errorf("failed to read password: %w", err)
- }
- pw = strings.TrimSpace(string(output))
- }
- u.User = url.UserPassword(u.User.Username(), pw)
- if c.CacheCmd {
- c.cache = pw
- }
-
- return u.String(), nil
-}
-
-type AccountConfig struct {
- Archive string
- CopyTo string
- Default string
- Postpone string
- From string
- Aliases string
- Name string
- Source string
- Folders []string
- FoldersExclude []string
- Params map[string]string
- Outgoing RemoteConfig
- SignatureFile string
- SignatureCmd string
- EnableFoldersSort bool `ini:"enable-folders-sort"`
- FoldersSort []string `ini:"folders-sort" delim:","`
- AddressBookCmd string `ini:"address-book-cmd"`
- SendAsUTC bool `ini:"send-as-utc"`
- LocalizedRe *regexp.Regexp
-
- // CheckMail
- CheckMail time.Duration `ini:"check-mail"`
- CheckMailCmd string `ini:"check-mail-cmd"`
- CheckMailTimeout time.Duration `ini:"check-mail-timeout"`
- CheckMailInclude []string `ini:"check-mail-include"`
- CheckMailExclude []string `ini:"check-mail-exclude"`
-
- // PGP Config
- PgpKeyId string `ini:"pgp-key-id"`
- PgpAutoSign bool `ini:"pgp-auto-sign"`
- PgpOpportunisticEncrypt bool `ini:"pgp-opportunistic-encrypt"`
-
- // AuthRes
- TrustedAuthRes []string `ini:"trusted-authres" delim:","`
-}
-
type BindingConfig struct {
Global *KeyBindings
AccountWizard *KeyBindings
@@ -287,127 +196,6 @@ func mapName(raw string) string {
return string(newstr)
}
-func loadAccountConfig(path string, accts []string) ([]AccountConfig, error) {
- file, err := ini.Load(path)
- if err != nil {
- // No config triggers account configuration wizard
- return nil, nil
- }
- file.NameMapper = mapName
-
- var accounts []AccountConfig
- for _, _sec := range file.SectionStrings() {
- if _sec == "DEFAULT" {
- continue
- }
- if len(accts) > 0 && !contains(accts, _sec) {
- continue
- }
- sec := file.Section(_sec)
- sourceRemoteConfig := RemoteConfig{}
- account := AccountConfig{
- Archive: "Archive",
- Default: "INBOX",
- Postpone: "Drafts",
- Name: _sec,
- Params: make(map[string]string),
- EnableFoldersSort: true,
- CheckMailTimeout: 10 * time.Second,
- // localizedRe contains a list of known translations for the common Re:
- LocalizedRe: regexp.MustCompile(`(?i)^((AW|RE|SV|VS|ODP|R): ?)+`),
- }
- if err = sec.MapTo(&account); err != nil {
- return nil, err
- }
- for key, val := range sec.KeysHash() {
- switch key {
- case "folders":
- folders := strings.Split(val, ",")
- sort.Strings(folders)
- account.Folders = folders
- case "folders-exclude":
- folders := strings.Split(val, ",")
- sort.Strings(folders)
- account.FoldersExclude = folders
- case "source":
- sourceRemoteConfig.Value = val
- case "source-cred-cmd":
- sourceRemoteConfig.PasswordCmd = val
- case "outgoing":
- account.Outgoing.Value = val
- case "outgoing-cred-cmd":
- account.Outgoing.PasswordCmd = val
- case "outgoing-cred-cmd-cache":
- cache, err := strconv.ParseBool(val)
- if err != nil {
- return nil, fmt.Errorf(
- "%s=%s %w", key, val, err)
- }
- account.Outgoing.CacheCmd = cache
- case "from":
- account.From = val
- case "aliases":
- account.Aliases = val
- case "copy-to":
- account.CopyTo = val
- case "archive":
- account.Archive = val
- case "enable-folders-sort":
- account.EnableFoldersSort, _ = strconv.ParseBool(val)
- case "pgp-key-id":
- account.PgpKeyId = val
- case "pgp-auto-sign":
- account.PgpAutoSign, _ = strconv.ParseBool(val)
- case "pgp-opportunistic-encrypt":
- account.PgpOpportunisticEncrypt, _ = strconv.ParseBool(val)
- case "address-book-cmd":
- account.AddressBookCmd = val
- case "subject-re-pattern":
- re, err := regexp.Compile(val)
- if err != nil {
- return nil, fmt.Errorf(
- "%s=%s %w", key, val, err)
- }
- account.LocalizedRe = re
- default:
- if key != "name" {
- account.Params[key] = val
- }
- }
- }
- if account.Source == "" {
- return nil, fmt.Errorf("Expected source for account %s", _sec)
- }
- if account.From == "" {
- return nil, fmt.Errorf("Expected from for account %s", _sec)
- }
-
- source, err := sourceRemoteConfig.ConnectionString()
- if err != nil {
- return nil, fmt.Errorf("Invalid source credentials for %s: %w", _sec, err)
- }
- account.Source = source
-
- _, err = account.Outgoing.parseValue()
- if err != nil {
- return nil, fmt.Errorf("Invalid outgoing credentials for %s: %w", _sec, err)
- }
-
- accounts = append(accounts, account)
- }
- if len(accts) > 0 {
- // Sort accounts struct to match the specified order, if we
- // have one
- if len(accounts) != len(accts) {
- return nil, errors.New("account(s) not found")
- }
- sort.Slice(accounts, func(i, j int) bool {
- return strings.ToLower(accts[i]) < strings.ToLower(accts[j])
- })
- }
- return accounts, nil
-}
-
// Set at build time
var shareDir string
@@ -898,23 +686,8 @@ func LoadConfigFromFile(root *string, accts []string) (*AercConfig, error) {
logging.Debugf("aerc.conf: [triggers] %#v", config.Triggers)
logging.Debugf("aerc.conf: [templates] %#v", config.Templates)
- filename = path.Join(*root, "accounts.conf")
- if !config.General.UnsafeAccountsConf {
- if err := checkConfigPerms(filename); err != nil {
- return nil, err
- }
- }
-
- accountsPath := path.Join(*root, "accounts.conf")
- logging.Infof("Parsing accounts configuration from %s", accountsPath)
- if accounts, err := loadAccountConfig(accountsPath, accts); err != nil {
+ if err := config.parseAccounts(*root, accts); err != nil {
return nil, err
- } else {
- config.Accounts = accounts
- }
-
- for _, acct := range config.Accounts {
- logging.Debugf("accounts.conf: [%s] from = %s", acct.Name, acct.From)
}
filename = path.Join(*root, "binds.conf")
@@ -1076,28 +849,6 @@ func (config *AercConfig) LoadBinds(binds *ini.File, baseName string, baseGroup
return nil
}
-// checkConfigPerms checks for too open permissions
-// printing the fix on stdout and returning an error
-func checkConfigPerms(filename string) error {
- info, err := os.Stat(filename)
- if errors.Is(err, os.ErrNotExist) {
- return nil // disregard absent files
- }
- if err != nil {
- return err
- }
-
- perms := info.Mode().Perm()
- // group or others have read access
- if perms&0o44 != 0 {
- fmt.Fprintf(os.Stderr, "The file %v has too open permissions.\n", filename)
- fmt.Fprintln(os.Stderr, "This is a security issue (it contains passwords).")
- fmt.Fprintf(os.Stderr, "To fix it, run `chmod 600 %v`\n", filename)
- return errors.New("account.conf permissions too lax")
- }
- return nil
-}
-
func parseLayout(layout string) [][]string {
rows := strings.Split(layout, ",")
l := make([][]string, len(rows))