From 519be36a2eda06e8c9f831779db47e4a83efbac8 Mon Sep 17 00:00:00 2001 From: Edward Durie Date: Tue, 13 Jan 2026 15:04:13 +1100 Subject: [PATCH 1/2] added untested support for systemd-creds --user switch; updated README.org to document this --- README.org | 22 +++++++++++++++++++--- src/core/config.lisp | 23 ++++++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README.org b/README.org index d04b83d..ef63aca 100644 --- a/README.org +++ b/README.org @@ -184,9 +184,9 @@ machine irc.libera.chat login yournick password your-secret-password CLatter will decrypt the file using GPG and look up the password by matching the server and nick. -**** systemd-creds (encrypted with TPM/host key) +**** systemd-creds (encrypted with TPM and/or host key) -Use =systemd-creds= to create a system credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This requires root privlages. +Use =systemd-creds= to create a system credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *requires* root privlages. 1. Create the encrypted credential: #+begin_src bash @@ -198,11 +198,27 @@ Use =systemd-creds= to create a system credential to encrypt your password. This 2. Update your config: #+begin_src lisp - :nickserv-pw (:systemd-cred "/home/you/.config/clatter/creds/nickserv.cred") + :nickserv-pw (:systemd-creds "/home/you/.config/clatter/creds/nickserv.cred") #+end_src CLatter will decrypt the credential file at startup using =systemd-creds decrypt=. +**** systemd-creds --user (encrypted with TPM and/or host key) + +Use =systemd-creds= with the =--user switch= to create a user credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *does not* require root privlages. + +1. Create the encrypted credential: + #+begin_src bash + mkdir -p ~/.config/clatter/creds + read -s -p "Enter NickServ password: " pw && echo -n "$pw" | \ + systemd-creds encrypt --user - ~/.config/clatter/creds/nickserv.cred && \ + echo -e "\nCredential saved" + #+end_src + +2. Update your config: + #+begin_src lisp + :nickserv-pw (:systemd-creds-user "/home/you/.config/clatter/creds/nickserv.cred") + #+end_src **** pass(1) (GPG encrypted) Use =pass(1)= the standard unix password manager, to store and encrypt your password. This works using GPG and the credential is portable. diff --git a/src/core/config.lisp b/src/core/config.lisp index b5e22a3..4d23b50 100644 --- a/src/core/config.lisp +++ b/src/core/config.lisp @@ -240,7 +240,7 @@ Returns plist with :login and :password, or nil if not found." (string-equal (getf entry :login) login))) (return entry))))))) -(defun read-systemd-cred (path) +(defun read-systemd-creds (path) "Decrypt a systemd-creds encrypted file and return its contents." (handler-case (string-trim '(#\Space #\Newline #\Return) @@ -249,6 +249,17 @@ Returns plist with :login and :password, or nil if not found." :output out :error-output nil))) (error () nil))) + +(defun read-systemd-creds-user (path) + "Decrypt a systemd-creds encrypted file with the --user switch and return its contents." + (handler-case + (string-trim '(#\Space #\Newline #\Return) + (with-output-to-string (out) + (uiop:run-program (list "systemd-creds" "--user" "decrypt" path "-") + :output out + :error-output nil))) + (error () nil))) + (defun read-password-store (password-name) "Resolve a password value from pass(1)" (handler-case @@ -263,6 +274,7 @@ Returns plist with :login and :password, or nil if not found." "Resolve a password value that may be: - :authinfo - read from ~/.authinfo or ~/.authinfo.gpg (requires server/nick) - (:systemd-creds \"/path/to/file.cred\") - decrypt using a system credential with systemd-creds + - (:systemd-creds-user \"/path/to/file.cred\") - decrypt using a user credential with systemd-creds - (:pass password-name) - decrypt using pass(1) - plain string - use directly - nil - no password" @@ -273,11 +285,16 @@ Returns plist with :login and :password, or nil if not found." (let ((entry (lookup-authinfo server nick))) (getf entry :password)))) - ;; (:systemd-cred "/path/to/file.cred") - decrypt using systemd-creds + ;; (:systemd-creds "/path/to/file.cred") - decrypt using systemd-creds ((and (listp pw) (eq (first pw) :systemd-creds)) (let ((cred-path (second pw))) (when cred-path - (read-systemd-cred cred-path)))) + (read-systemd-creds cred-path)))) + + ((and (listp pw) (eq (first pw) :systemd-creds-user)) + (let ((cred-path (second pw))) + (when cred-path + (read-systemd-creds-user cred-path)))) ;; (:pass "password-name") - decrypt using pass(1) ((and (listp pw) (eq (first pw) :pass)) From 17610d447d8c7432fe03f8e5d50e6f93bc8f47e8 Mon Sep 17 00:00:00 2001 From: Edward Durie Date: Tue, 13 Jan 2026 19:59:21 +1100 Subject: [PATCH 2/2] doc strings and additional documentation of systemd-creds and system-creds-user --- README.org | 4 ++-- src/core/config.lisp | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/README.org b/README.org index ef63aca..2264d8e 100644 --- a/README.org +++ b/README.org @@ -186,7 +186,7 @@ CLatter will decrypt the file using GPG and look up the password by matching the **** systemd-creds (encrypted with TPM and/or host key) -Use =systemd-creds= to create a system credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *requires* root privlages. +Use =systemd-creds= to create a SYSTEM credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *requires* root privilages. 1. Create the encrypted credential: #+begin_src bash @@ -205,7 +205,7 @@ CLatter will decrypt the credential file at startup using =systemd-creds decrypt **** systemd-creds --user (encrypted with TPM and/or host key) -Use =systemd-creds= with the =--user switch= to create a user credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *does not* require root privlages. +Use =systemd-creds= with the =--user switch= to create a USER credential to encrypt your password. This ties the credential to your machine and doesn't require GPG. This *does not* require root privilages. 1. Create the encrypted credential: #+begin_src bash diff --git a/src/core/config.lisp b/src/core/config.lisp index 4d23b50..17341f5 100644 --- a/src/core/config.lisp +++ b/src/core/config.lisp @@ -240,6 +240,7 @@ Returns plist with :login and :password, or nil if not found." (string-equal (getf entry :login) login))) (return entry))))))) +;; systemd-creds support for reading from a SYSTEM credential. (defun read-systemd-creds (path) "Decrypt a systemd-creds encrypted file and return its contents." (handler-case @@ -250,8 +251,9 @@ Returns plist with :login and :password, or nil if not found." :error-output nil))) (error () nil))) +;; systemd-creds support for reading from a USER credential. (defun read-systemd-creds-user (path) - "Decrypt a systemd-creds encrypted file with the --user switch and return its contents." + "Decrypt a systemd-creds encrypted file with the --user switch and return its contents." (handler-case (string-trim '(#\Space #\Newline #\Return) (with-output-to-string (out) @@ -259,7 +261,7 @@ Returns plist with :login and :password, or nil if not found." :output out :error-output nil))) (error () nil))) - +;; pass(1) support for reading from a credential stored in a .gpg file. (defun read-password-store (password-name) "Resolve a password value from pass(1)" (handler-case @@ -285,18 +287,19 @@ Returns plist with :login and :password, or nil if not found." (let ((entry (lookup-authinfo server nick))) (getf entry :password)))) - ;; (:systemd-creds "/path/to/file.cred") - decrypt using systemd-creds + ;; (:systemd-creds "/path/to/file.cred") - decrypt using systemd-creds (root privilages required) ((and (listp pw) (eq (first pw) :systemd-creds)) (let ((cred-path (second pw))) (when cred-path (read-systemd-creds cred-path)))) + ;; (:systemd-creds-user "/path/to/file.cred") - decrypt using systemd-creds --user (no root privilages required) ((and (listp pw) (eq (first pw) :systemd-creds-user)) (let ((cred-path (second pw))) (when cred-path (read-systemd-creds-user cred-path)))) - ;; (:pass "password-name") - decrypt using pass(1) + ;; (:pass "password-name") - decrypt using pass(1) - gpg and pinentry required. ((and (listp pw) (eq (first pw) :pass)) (let ((password-name (second pw))) (when password-name