Storing passwords in plaintext in your configuration file is dangerous!
This patch adds support for fetching a password from an external
command (i.e. `gpg`, `pass`, `gopass`).
---
Updated the credential execution to run the specified credential helper
command with "sh -c" to allow arbitrary shell commands, as per previous
email. Let me know if this is acceptable or you'd still rather have a
separate shell script file like ~/.config/senpai/password
README.md | 2 ++
config.go | 19 +++++++++++++++++++
doc/senpai.5.scd | 21 +++++++++++++++------
3 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index 99c80bd..e451228 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,8 @@ cat <<EOF >~/.config/senpai/senpai.yaml
addr: irc.libera.chat
nick: senpai
password: "my password can't be this cute"
+# alternatively, specify a command to fetch your password:
+# passcmd: "gopass show irc/<username>"
EOF
go run ./cmd/senpai
```
diff --git a/config.go b/config.go
index 2b05e07..03966e8 100644
--- a/config.go
+++ b/config.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"io/ioutil"
+ "os/exec"
"strconv"
"strings"
@@ -52,6 +53,7 @@ type Config struct {
Real string
User string
Password *string
+ Passcmd string
NoTLS bool `yaml:"no-tls"`
Channels []string
@@ -88,6 +90,13 @@ func ParseConfig(buf []byte) (cfg Config, err error) {
if cfg.Real == "" {
cfg.Real = cfg.Nick
}
+ if cfg.Passcmd != "" {
+ password, err := RunPasscmd(cfg.Passcmd)
+ if err != nil {
+ return cfg, err
+ }
+ cfg.Password = &password
+ }
if cfg.NickColWidth <= 0 {
cfg.NickColWidth = 16
}
@@ -114,3 +123,13 @@ func LoadConfigFile(filename string) (cfg Config, err error) {
}
return
}
+
+func RunPasscmd(command string) (password string, err error) {
+ cmd := exec.Command("sh", "-c", command)
+ stdout, err := cmd.Output()
+ if err == nil {
+ password = strings.TrimSuffix(string(stdout), "\n")
+ }
+
+ return
+}
diff --git a/doc/senpai.5.scd b/doc/senpai.5.scd
index 5658707..49fdac0 100644
--- a/doc/senpai.5.scd
+++ b/doc/senpai.5.scd
@@ -31,7 +31,15 @@ Some settings are required, the others are optional.
authentication. By default, the value of *nick* is used.
*password*
- Your password, used for SASL authentication.
+ Your password, used for SASL authentication. See also *passcmd*.
+
+*passcmd*
+ Alternatively to providing your SASL authentication password directly in plaintext,
+ you can specify a command to be run to fetch the password at runtime. This is useful
+ if you store your passwords in a separate (probably encrypted) file using `gpg` or
+ a command line password manager such as `pass` or `gopass`. If a *passcmd* is provided,
+ the value of *password* will be ignored and the output of *passcmd* will be used for
+ login.
*channels*
A list of channel names that senpai will automatically join at startup and
@@ -125,17 +133,18 @@ addr: irc.libera.chat
nick: Guest123456
```
-A more advanced configuration file that enables SASL authentication, sends
-notifications on highlight and decreases the width of the nick column to 12
-(note: _swaymsg_ is specific to sway, a wayland compositor. Use whatever you
-need to know if the terminal emulator that runs senpai has focus):
+A more advanced configuration file that enables SASL authentication, fetches the password
+from an external program instead of storing in plaintext, sends notifications on highlight
+and decreases the width of the nick column to 12 (note: _swaymsg_ is specific to sway,
+a wayland compositor. Use whatever you need to know if the terminal emulator that runs
+senpai has focus):
```
addr: irc.libera.chat
nick: Guest123456
user: senpai
real: Guest von Lenon
-password: A secure password, I guess?
+passcmd: "gopass show irc/guest" # use your favorite CLI password solution here
channels: ["#rahxephon"]
highlights:
- guest
--
2.33.0