;;; -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (require 'f) (defvar bd/password-store-kill-ring-pointer nil "The tail of the kill ring whose car is the password.") (defvar bd/password-store-time-before-clear 10 "The time before a killed password is cleared.") (defun bd/password-store-list () "List password-store entries." (mapcar (lambda (file) (f-no-ext (f-relative file "~/.password-store/"))) (f-files "~/.password-store" (lambda (file) (equal (f-ext file) "gpg")) t))) (defun bd/password-store-clear (id) "Clears the most recent password copied to the kill ring, printing ID." (when bd/password-store-kill-ring-pointer (setcar bd/password-store-kill-ring-pointer nil) (kill-new "") (setq bd/password-store-kill-ring-pointer nil) (message "Cleared password for %s from the kill ring and system clipboard." id))) (defun bd/read-password (id) "Read the password-store entry corresponding to ID." (bd/password-store-clear "id") (let ((find-file-hook (remq 'recentf-track-opened-file find-file-hook))) (find-file (concat "~/.password-store/" id ".gpg")) (goto-char 1) (kill-new (buffer-substring-no-properties (line-beginning-position) (line-end-position))) (setq bd/password-store-kill-ring-pointer kill-ring-yank-pointer) (kill-buffer (current-buffer)) (run-at-time bd/password-store-time-before-clear nil (lambda () (funcall #'bd/password-store-clear id))) (message "Copied password for %s to the kill ring and system clipboard. Will clear in %s seconds." id bd/password-store-time-before-clear))) (defun bd/password () "Interactively select a password-store password." (interactive) (bd/read-password (completing-read "Yank: " (bd/password-store-list)))) (use-package pinentry :defer 1 :config (pinentry-start) (defun pinentry-toggle () "Stops and starts Pinentry service. Workaround for a bug I've encountered." (interactive) (pinentry-stop) (pinentry-start)) (setopt enable-recursive-minibuffers t pinentry-popup-prompt-window nil)) (provide 'bd--gpg) ;;; bd--gpg.el ends here