Rewrite tools/password-store API
This commit is contained in:
parent
3b4aca6270
commit
e88f84fd02
3 changed files with 135 additions and 58 deletions
|
@ -1,77 +1,142 @@
|
|||
;;; tools/password-store/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/open ()
|
||||
(interactive)
|
||||
(cond ((featurep! :completion ivy)
|
||||
(+pass/ivy))
|
||||
((featurep! :completion helm)
|
||||
(helm-pass))
|
||||
(t
|
||||
(pass))))
|
||||
|
||||
;;;###autoload
|
||||
(defalias '+pass--get-entry
|
||||
#'auth-source-pass-parse-entry)
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass-get-field (entry fields)
|
||||
(if-let* ((data (if (listp entry) entry (+pass--get-entry entry))))
|
||||
(cl-loop for key in (doom-enlist fields)
|
||||
when (assoc key data)
|
||||
return (cdr it))
|
||||
(error "Couldn't find entry: %s" entry)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass-get-user (entry)
|
||||
(+pass-get-field entry +pass-user-fields))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass-get-secret (entry)
|
||||
(+pass-get-field entry 'secret))
|
||||
|
||||
(defun +pass-ivy-action--open-url (entry)
|
||||
(defun +pass--open-url (entry)
|
||||
(if-let* ((url (+pass-get-field entry +pass-url-fields)))
|
||||
(and (or (string-match-p "https?://" url)
|
||||
(error "Field for %s doesn't look like an url" item))
|
||||
(browse-url url))
|
||||
(error "url not found.")))
|
||||
|
||||
(defun +pass-ivy-action--get-field (item)
|
||||
(let* ((data (+pass--get-entry item))
|
||||
(field (if data (completing-read "Field: " (mapcar #'car data) nil t))))
|
||||
(if data
|
||||
(progn
|
||||
(password-store-clear)
|
||||
(message "Copied %s's %s field to clipboard. Will clear in %s seconds"
|
||||
item field (password-store-timeout))
|
||||
(kill-new (+pass-get-field data field))
|
||||
(setq password-store-timeout-timer
|
||||
(run-at-time (password-store-timeout) nil 'password-store-clear)))
|
||||
(error "Couldn't find entry: %s" item))))
|
||||
(defun +pass--copy (entry field text)
|
||||
(password-store-clear)
|
||||
(message "Copied %s's %s field to clipboard. Will clear in %s seconds"
|
||||
entry field (password-store-timeout))
|
||||
(kill-new text)
|
||||
(setq password-store-timeout-timer
|
||||
(run-at-time (password-store-timeout) nil 'password-store-clear)))
|
||||
|
||||
(defun +pass-ivy-action--copy-username (entry)
|
||||
(defun +pass--copy-username (entry)
|
||||
(if-let* ((user (+pass-get-field entry +pass-user-fields)))
|
||||
(progn (password-store-clear)
|
||||
(message "Copied username to the kill ring.")
|
||||
(kill-new user))
|
||||
(error "Username not found.")))
|
||||
|
||||
(after! ivy
|
||||
(ivy-add-actions
|
||||
'+pass/ivy
|
||||
'(("o" password-store-copy "copy password")
|
||||
("e" password-store-edit "edit entry")
|
||||
("u" +pass-ivy-action--copy-username "copy username")
|
||||
("b" +pass-ivy-action--open-url "open url in browser")
|
||||
("f" +pass-ivy-action--get-field "get field"))))
|
||||
(defun +pass--completing-read-field (entry)
|
||||
(let* ((data (+pass-get-entry entry))
|
||||
(field (if data (completing-read "Field: " (mapcar #'car data) nil t))))
|
||||
(+pass-get-field data field)))
|
||||
|
||||
|
||||
;;
|
||||
;; API
|
||||
;;
|
||||
|
||||
;;;###autoload (autoload 'auth-source-pass-parse-entry "auth-source-pass" nil nil t)
|
||||
;;;###autoload
|
||||
(defalias '+pass-get-entry #'auth-source-pass-parse-entry)
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/ivy (&optional browse-url)
|
||||
(defun +pass-get-field (entry fields &optional noerror)
|
||||
"Fetches the value of a field. FIELDS can be a list of string field names or a
|
||||
single one. If a list, the first field found will be returned. Will error out
|
||||
otherwise, unless NOERROR is non-nill."
|
||||
(if-let* ((data (if (listp entry) entry (+pass-get-entry entry))))
|
||||
(cl-loop for key in (doom-enlist fields)
|
||||
when (assoc key data)
|
||||
return (cdr it))
|
||||
(unless noerror
|
||||
(error "Couldn't find entry: %s" entry))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass-get-user (entry)
|
||||
"Fetches the user field from ENTRY. Each of `+pass-user-fields' are tried in
|
||||
search of your username. May prompt for your gpg passphrase."
|
||||
(+pass-get-field entry +pass-user-fields))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass-get-secret (entry)
|
||||
"Fetches your secret from ENTRY. May prompt for your gpg passphrase."
|
||||
(+pass-get-field entry 'secret))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
;;
|
||||
|
||||
;;;###autoload (autoload 'password-store-list "pass" nil nil t)
|
||||
;;;###autoload (autoload 'password-store--completing-read "password-store" nil nil t)
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/edit-entry (entry)
|
||||
"Interactively search for and open a pass entry for editing."
|
||||
(interactive
|
||||
(list (password-store--completing-read)))
|
||||
(find-file (concat (expand-file-name entry (password-store-dir)) ".gpg")))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/copy-field (entry)
|
||||
"Interactively search for an entry and copy a particular field to your
|
||||
clipboard."
|
||||
(interactive
|
||||
(list (password-store--completing-read)))
|
||||
(let* ((data (+pass-get-entry entry))
|
||||
(field (if data (completing-read "Field: " (mapcar #'car data) nil t))))
|
||||
(+pass--copy entry field (+pass-get-field data field))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/copy-secret (entry)
|
||||
"Interactively search for an entry and copy its secret/password to your
|
||||
clipboard."
|
||||
(interactive
|
||||
(list (password-store--completing-read)))
|
||||
(+pass--copy entry 'secret (+pass-get-secret entry)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/copy-user (entry)
|
||||
"Interactively search for an entry and copy the login to your clipboard. The
|
||||
fields in `+pass-user-fields' is used to find the login field."
|
||||
(interactive
|
||||
(list (password-store--completing-read)))
|
||||
(+pass--copy-username entry))
|
||||
|
||||
;;;###autoload
|
||||
(defun +pass/browse-url (entry)
|
||||
"Interactively search for an entry and open its url in your browser. The
|
||||
fields in `+pass-url-fields' is used to find the url field."
|
||||
(interactive
|
||||
(list (password-store--completing-read)))
|
||||
(+pass--open-url entry))
|
||||
|
||||
|
||||
;;
|
||||
;; Ivy interface
|
||||
;;
|
||||
|
||||
(defun +pass/ivy (arg)
|
||||
"TODO"
|
||||
(interactive "P")
|
||||
(ivy-read "Pass: " (password-store-list)
|
||||
:action (if browse-url
|
||||
:action (if arg
|
||||
#'password-store-url
|
||||
#'password-store-copy)
|
||||
:caller '+pass/ivy))
|
||||
|
||||
(after! ivy
|
||||
(ivy-add-actions
|
||||
'+pass/ivy
|
||||
'(("o" password-store-copy "copy password")
|
||||
("e" +pass/edit-entry "edit entry")
|
||||
("u" +pass/copy-login "copy username")
|
||||
("b" +pass/copy-url "open url in browser")
|
||||
("f" +pass/copy-field "get field"))))
|
||||
|
||||
|
||||
;;
|
||||
;; TODO Helm interface
|
||||
;;
|
||||
|
||||
;; (defun +pass/helm ()
|
||||
;; (interactive)
|
||||
;; )
|
||||
|
||||
|
|
|
@ -14,11 +14,19 @@
|
|||
;; `password-store'
|
||||
(setq password-store-password-length 12)
|
||||
|
||||
;; Fix hard-coded password-store location; respect PASSWORD_STORE_DIR envvar
|
||||
(defun +password-store*read-entry (entry)
|
||||
"Return a string with the file content of ENTRY."
|
||||
(with-temp-buffer
|
||||
(insert-file-contents
|
||||
(expand-file-name (format "%s.gpg" entry) (password-store-dir)))
|
||||
(buffer-substring-no-properties (point-min) (point-max))))
|
||||
(advice-add #'auth-source-pass--read-entry :override #'+password-store*read-entry)
|
||||
|
||||
|
||||
;; `pass'
|
||||
(def-package! pass
|
||||
:defer t
|
||||
:config
|
||||
(after! pass
|
||||
(set! :env "PASSWORD_STORE_DIR")
|
||||
(set! :evil-state 'pass-mode 'emacs)
|
||||
(set! :popup "^\\*Password-Store"
|
||||
'((side . left) (size . 0.25))
|
||||
|
|
|
@ -3,9 +3,13 @@
|
|||
|
||||
(package! pass)
|
||||
(package! password-store)
|
||||
(package! password-store-otp)
|
||||
|
||||
(when (and EMACS26+ (featurep! +auth))
|
||||
;; `auto-source-pass' is built into Emacs 26+
|
||||
(unless EMACS26+
|
||||
(package! auth-source-pass))
|
||||
|
||||
(when (featurep! :completion ivy)
|
||||
(package! ivy-pass))
|
||||
(when (featurep! :completion helm)
|
||||
(package! helm-pass))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue