password-store

Simple password manager using gpg and ordinary unix directories
git clone https://git.zx2c4.com/password-store
Log | Files | Refs | README | LICENSE

commit b5e965a838bb68c1227caa2cdd874ba496f10149
parent 28cec11f1dbe6c4273d30370af45b69c9f408386
Author: Niall Dooley <dooleyn@gmail.com>
Date:   Fri,  1 Dec 2023 10:43:36 +0100

emacs: Clear both, kill-ring & the system clipboard

Prior to this commit, after the timeout expired, the password was
cleared from the kill-ring but remained in the system clipboard.

To ensure passwords are also cleared from the system clipboard,
`(kill-new "")` has been added inside the `password-store-clear`
function when clearing the kill-ring.

- Ensure that passwords are cleared from the system clipboard as well [1].
- Declare `password-store-timeout` obsolete since v2.0.4 [2].
- Header and docstring improvements [3].
- Rename argument in `password-store--run-init` [4].
- Bump version to 2.3.2.

Reported by Niall Dooley <dooleyn@gmail.com>:

[1] https://lists.zx2c4.com/pipermail/password-store/2023-November/004800.html
[2] https://lists.zx2c4.com/pipermail/password-store/2023-November/004798.html
[3] https://lists.zx2c4.com/pipermail/password-store/2023-November/004791.html
[4] https://lists.zx2c4.com/pipermail/password-store/2023-November/004799.html

Diffstat:
Mcontrib/emacs/CHANGELOG.md | 5+++++
Mcontrib/emacs/password-store.el | 126+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
2 files changed, 77 insertions(+), 54 deletions(-)

diff --git a/contrib/emacs/CHANGELOG.md b/contrib/emacs/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.3.2 + +* (bugfix) Ensure the system clipboard is cleared after + the timeout expired. + # 2.3.1 * (bug) Drop dependency on s library. diff --git a/contrib/emacs/password-store.el b/contrib/emacs/password-store.el @@ -4,32 +4,34 @@ ;; Author: Svend Sorensen <svend@svends.net> ;; Maintainer: Tino Calancha <tino.calancha@gmail.com> -;; Version: 2.3.1 +;; Version: 2.3.2 ;; URL: https://www.passwordstore.org/ -;; Package-Requires: ((emacs "26") (with-editor "2.5.11")) -;; Keywords: tools pass password password-store +;; Package-Requires: ((emacs "26.1") (with-editor "2.5.11")) +;; SPDX-License-Identifier: GPL-3.0-or-later +;; Keywords: tools pass password password-store gpg ;; This file is not part of GNU Emacs. -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of +;; the License, or (at your option) any later version. -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. +;; This program is distributed in the hope that it will be +;; useful, but WITHOUT ANY WARRANTY; without even the implied +;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +;; PURPOSE. See the GNU General Public License for more details. -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. +;; You should have received a copy of the GNU General Public +;; License along with this program. If not, see +;; <http://www.gnu.org/licenses/>. ;;; Commentary: -;; This package provides functions for working with pass ("the -;; standard Unix password manager"). -;; -;; http://www.passwordstore.org/ +;; This package provides and Emacs interface for working with +;; pass ("the standard Unix password manager"). + +;; https://www.passwordstore.org/ ;;; Code: @@ -37,9 +39,17 @@ (require 'auth-source-pass) (defgroup password-store '() - "Emacs mode for password-store." + "Emacs mode for password-store. +The standard Unix password manager" :prefix "password-store-" - :group 'password-store) + :group 'password-store + :link '(url-link :tag "Description" "https://www.passwordstore.org/") + :link '(url-link :tag "Download" "https://melpa.org/#/password-store") + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "password-store" "@" "lists.zx2c4" ".com?subject= +password-store.el bug: \ +&body=Describe bug here, starting with `emacs -q'. \ +Don't forget to mention your Emacs and library versions."))) (defcustom password-store-password-length 25 "Default password length." @@ -55,7 +65,7 @@ :type 'number) (defcustom password-store-url-field "url" - "Field name used in the files to indicate an url." + "Field name used in the files to indicate a URL." :group 'password-store :type 'string) @@ -67,17 +77,20 @@ "Timer for clearing clipboard.") (defun password-store-timeout () - "Number of seconds to wait before clearing the password. + "Number of seconds to wait before restoring the clipboard. + +This function just returns +`password-store-time-before-clipboard-restore'. Kept for +backward compatibility with other libraries." +password-store-time-before-clipboard-restore) -This function just returns `password-store-time-before-clipboard-restore'. -Kept for backward compatibility with other libraries." - password-store-time-before-clipboard-restore) +(make-obsolete 'password-store-timeout 'password-store-time-before-clipboard-restore "2.0.4") (defun password-store--run-1 (callback &rest args) "Run pass with ARGS. -Nil arguments are ignored. Calls CALLBACK with the output on success, -or outputs error message on failure." +Nil arguments are ignored. Calls CALLBACK with the output on +success, or outputs error message on failure." (let ((output "")) (make-process :name "password-store-gpg" @@ -118,9 +131,9 @@ Nil arguments are ignored. Output is discarded." (cons password-store-executable (delq nil args)) " ")))) -(defun password-store--run-init (gpg-ids &optional folder) +(defun password-store--run-init (gpg-ids &optional subdir) (apply 'password-store--run "init" - (if folder (format "--path=%s" folder)) + (if subdir (format "--path=%s" subdir)) gpg-ids)) (defun password-store--run-list (&optional subdir) @@ -230,8 +243,8 @@ ENTRY is the name of a password-store entry." (defun password-store-get (entry &optional callback) "Return password for ENTRY. -Returns the first line of the password data. -When CALLBACK is non-`NIL', call CALLBACK with the first line instead." +Returns the first line of the password data. When CALLBACK is +non-`NIL', call CALLBACK with the first line instead." (let* ((inhibit-message t) (secret (auth-source-pass-get 'secret entry))) (if (not callback) secret @@ -242,9 +255,10 @@ When CALLBACK is non-`NIL', call CALLBACK with the first line instead." ;;;###autoload (defun password-store-get-field (entry field &optional callback) "Return FIELD for ENTRY. -FIELD is a string, for instance \"url\". -When CALLBACK is non-`NIL', call it with the line associated to FIELD instead. -If FIELD equals to symbol secret, then this function reduces to `password-store-get'." +FIELD is a string, for instance \"url\". When CALLBACK is +non-`NIL', call it with the line associated to FIELD instead. If +FIELD equals to symbol secret, then this function reduces to +`password-store-get'." (let* ((inhibit-message t) (secret (auth-source-pass-get field entry))) (if (not callback) secret @@ -257,12 +271,12 @@ If FIELD equals to symbol secret, then this function reduces to `password-store- (defun password-store-clear (&optional field) "Clear secret in the kill ring. -Optional argument FIELD, a symbol or a string, describes -the stored secret to clear; if nil, then set it to 'secret. -Note, FIELD does not affect the function logic; it is only used -to display the message: +Optional argument FIELD, a symbol or a string, describes the +stored secret to clear; if nil, then set it to 'secret. Note, +FIELD does not affect the function logic; it is only used to +display the message: -\(message \"Field %s cleared.\" field)." +\(message \"Field %s cleared from kill ring and system clipboard.\" field)." (interactive "i") (unless field (setq field 'secret)) (when password-store-timeout-timer @@ -270,14 +284,15 @@ to display the message: (setq password-store-timeout-timer nil)) (when password-store-kill-ring-pointer (setcar password-store-kill-ring-pointer "") + (kill-new "") (setq password-store-kill-ring-pointer nil) - (message "Field %s cleared." field))) + (message "Field %s cleared from kill ring and system clipboard." field))) (defun password-store--save-field-in-kill-ring (entry secret field) (password-store-clear field) (kill-new secret) (setq password-store-kill-ring-pointer kill-ring-yank-pointer) - (message "Copied %s for %s to the kill ring. Will clear in %s seconds." + (message "Copied %s for %s to the kill ring and system clipboard. Will clear in %s seconds." field entry password-store-time-before-clipboard-restore) (setq password-store-timeout-timer (run-at-time password-store-time-before-clipboard-restore nil @@ -287,9 +302,10 @@ to display the message: (defun password-store-copy (entry) "Add password for ENTRY into the kill ring. -Clear previous password from the kill ring. Pointer to the kill ring -is stored in `password-store-kill-ring-pointer'. Password is cleared -after `password-store-time-before-clipboard-restore' seconds." +Clear previous password from the kill ring. Pointer to the kill +ring is stored in `password-store-kill-ring-pointer'. Password +is cleared after `password-store-time-before-clipboard-restore' +seconds." (interactive (list (password-store--completing-read t))) (password-store-get entry @@ -300,10 +316,12 @@ after `password-store-time-before-clipboard-restore' seconds." (defun password-store-copy-field (entry field) "Add FIELD for ENTRY into the kill ring. -Clear previous secret from the kill ring. Pointer to the kill ring is -stored in `password-store-kill-ring-pointer'. Secret field is cleared -after `password-store-timeout' seconds. -If FIELD equals to symbol secret, then this function reduces to `password-store-copy'." +Clear previous secret from the kill ring. Pointer to the kill +ring is stored in `password-store-kill-ring-pointer'. Secret +field is cleared after +`password-store-time-before-clipboard-restore' seconds. If FIELD +equals to symbol secret, then this function reduces to +`password-store-copy'." (interactive (let ((entry (password-store--completing-read))) (list entry (password-store-read-field entry)))) @@ -344,8 +362,8 @@ Default PASSWORD-LENGTH is `password-store-password-length'." (interactive (list (password-store--completing-read) (and current-prefix-arg (abs (prefix-numeric-value current-prefix-arg))))) - ;; A message with the output of the command is not printed because - ;; the output contains the password. + ;; A message with the output of the command is not printed + ;; because the output contains the password. (password-store--run-generate entry (or password-length password-store-password-length) @@ -361,8 +379,8 @@ Default PASSWORD-LENGTH is `password-store-password-length'." (and current-prefix-arg (abs (prefix-numeric-value current-prefix-arg))))) - ;; A message with the output of the command is not printed because - ;; the output contains the password. + ;; A message with the output of the command is not printed + ;; because the output contains the password. (password-store--run-generate entry (or password-length password-store-password-length) @@ -371,7 +389,7 @@ Default PASSWORD-LENGTH is `password-store-password-length'." ;;;###autoload (defun password-store-remove (entry) - "Remove existing password for ENTRY." + "Remove ENTRY." (interactive (list (password-store--completing-read t))) (message "%s" (password-store--run-remove entry t))) @@ -384,13 +402,13 @@ Default PASSWORD-LENGTH is `password-store-password-length'." ;;;###autoload (defun password-store-version () - "Show version of pass executable." + "Show version of `password-store-executable'." (interactive) (message "%s" (password-store--run-version))) ;;;###autoload (defun password-store-url (entry) - "Browse URL stored in ENTRY." + "Load URL for ENTRY." (interactive (list (password-store--completing-read t))) (let ((url (password-store-get-field entry password-store-url-field))) (if url (browse-url url)