This commit is contained in:
ry
2022-01-11 18:05:13 -08:00
parent 2046befee2
commit 8e7b654716
846 changed files with 71287 additions and 4 deletions

View File

@@ -0,0 +1,55 @@
#+TITLE: tools/pass
#+DATE: May 4, 2020
#+SINCE: V2.0.9
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#maintainers][Maintainers]]
- [[#module-flags][Module Flags]]
- [[#plugins][Plugins]]
- [[#hacks][Hacks]]
- [[#prerequisites][Prerequisites]]
- [[#features][Features]]
- [[#configuration][Configuration]]
- [[#troubleshooting][Troubleshooting]]
* Description
+ Manage passwords on ~pass~ with power of ~doom~.
+ You can open ~pass~ by =M-x pass=
** Maintainers
This module has no dedicated maintainers.
** Module Flags
+ ~+auth~ to enable ~auth-source-pass~
** Plugins
# A list of linked plugins
+ [[https://github.com/NicolasPetton/pass][pass]]
+ [[https://github.com/zx2c4/password-store][password-store]]
+ [[https://github.com/volrath/password-store-otp.el][password-store-otp]]
+ [[https://github.com/DamienCassou/auth-password-store][auth-source-pass (auth-password-store)]]
+ =:completion ivy=
+ [[https://github.com/ecraven/ivy-pass][ivy-pass]]
+ =:completion helm=
+ [[https://github.com/emacs-helm/helm-pass][helm-pass]]
** Hacks
In ~pass-mode~ ~evil~ is put into ~emacs~ state so shown keybindings works correctly, but some keybindings is more ~evil~.
| keybinding | action |
|------------+-------------------------|
| j | pass-next-entry |
| k | pass-previous-entry |
| d | pass-kill |
| C-j | pass-next-directory |
| C-k | pass-previous-directory |
* Prerequisites
+ This module requires that [[https://www.passwordstore.org/][pass]] is installed and setup correctly.
* TODO Features
* TODO Configuration
* Troubleshooting
No known issues.

View File

@@ -0,0 +1,21 @@
;;; tools/pass/autoload/consult.el -*- lexical-binding: t; -*-
;;;###if (featurep! :completion vertico)
;;;###autoload
(defun +pass/consult (arg pass)
"TODO"
(interactive
(list current-prefix-arg
(progn
(require 'consult)
(consult--read (password-store-list)
:prompt "Pass: "
:sort nil
:require-match t
:category 'pass))))
(funcall (if arg
#'password-store-url
#'password-store-copy)
pass))
;; TODO Add embark actions to +pass/consult

View File

@@ -0,0 +1,21 @@
;;; tools/pass/autoload/ivy.el -*- lexical-binding: t; -*-
;;;###if (featurep! :completion ivy)
;;;###autoload
(defun +pass/ivy (arg)
"Complete and act on password store entries."
(interactive "P")
(ivy-read "Pass: " (password-store-list)
: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" password-store-edit "edit entry")
("u" +pass/copy-user "copy username")
("b" password-store-url "open url in browser")
("f" password-store-copy-field "get field"))))

View File

@@ -0,0 +1,67 @@
;;; tools/pass/autoload/pass.el -*- lexical-binding: t; -*-
(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.")))
;;
;; API
;;;###autoload (autoload 'auth-source-pass-parse-entry "auth-source-pass")
;;;###autoload
(defalias '+pass-get-entry #'auth-source-pass-parse-entry)
;;;###autoload
(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-dir "password-store")
;;;###autoload (autoload 'password-store-list "password-store")
;;;###autoload (autoload 'password-store--completing-read "password-store")
;;;###autoload
(define-obsolete-function-alias '+pass/edit-entry #'password-store-edit "21.12")
;;;###autoload
(define-obsolete-function-alias '+pass/copy-field #'password-store-copy-field "21.12")
;;;###autoload
(define-obsolete-function-alias '+pass/copy-secret #'password-store-copy "21.12")
;;;###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
(define-obsolete-function-alias '+pass/browse-url #'password-store-url "21.12")

View File

@@ -0,0 +1,39 @@
;;; tools/pass/config.el -*- lexical-binding: t; -*-
(defvar +pass-user-fields '("login" "user" "username" "email")
"A list of fields for `+pass/ivy' to search for the username.")
(defvar +pass-url-fields '("url" "site" "location")
"A list of fields for `+pass/ivy' to search for the username.")
;;
;; Packages
;;;###package password-store
(setq password-store-password-length 12)
;; Fix hard-coded password-store location; respect PASSWORD_STORE_DIR envvar
(defadvice! +pass--respect-pass-dir-envvar-a (entry)
"Return a string with the file content of ENTRY."
:override #'auth-source-pass--read-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))))
(after! pass
(set-evil-initial-state! 'pass-mode 'emacs)
(set-popup-rule! "^\\*Password-Store" :side 'left :size 0.25 :quit nil)
(define-key! pass-mode-map
"j" #'pass-next-entry
"k" #'pass-prev-entry
"d" #'pass-kill
"\C-j" #'pass-next-directory
"\C-k" #'pass-prev-directory))
;; Is built into Emacs 26+
(when (featurep! +auth)
(auth-source-pass-enable))

View File

@@ -0,0 +1,11 @@
;; -*- no-byte-compile: t; -*-
;;; tools/pass/packages.el
(package! pass :pin "5651da53137db9adcb125b4897c2fe27eeb4368d")
(package! password-store :pin "04cd3023f48cd203f6c0193e57a427226e8b431c")
(package! password-store-otp :pin "04998c8578a060ab4a4e8f46f2ee0aafad4ab4d5")
(when (featurep! :completion ivy)
(package! ivy-pass :pin "5b523de1151f2109fdd6a8114d0af12eef83d3c5"))
(when (featurep! :completion helm)
(package! helm-pass :pin "4ce46f1801f2e76e53482c65aa0619d427a3fbf9"))

View File

@@ -0,0 +1,41 @@
;; -*- no-byte-compile: t; -*-
;;; tools/pass/test/test-pass.el
(describe "tools/pass"
(before-all
(load! "../autoload"))
(before-each
(spy-on 'auth-source-pass-parse-entry :and-call-fake
(lambda (entry)
(when (equal entry "fake/source")
'((secret . "defuse-account-gad")
("login" . "HL2532")
("alt-login" . "hlissner")
("email" . "henrik@lissner.net")
("url" . "https://some-place.net/login"))))))
(describe "get field"
(it "returns specific fields"
(expect (+pass-get-field "fake/source" "email")
:to-equal "henrik@lissner.net"))
(it "returns first existing of a list of fields"
(expect (+pass-get-field "fake/source" '("alt-login" "email"))
:to-equal "hlissner")
(expect (+pass-get-field "fake/source" '("username" "email"))
:to-equal "henrik@lissner.net"))
(it "returns nil for missing fields"
(expect (+pass-get-field "fake/source" '("x" "y" "z"))
:to-be nil))
(it "throws error on missing entries"
(expect (+pass-get-field "nonexistent/source" "login")
:to-throw)))
(describe "get user/secret"
(it "returns the user"
(let ((+pass-user-fields '("login" "user" "username" "email")))
(expect (+pass-get-user "fake/source")
:to-equal "HL2532")))
(it "returns the secret"
(expect (+pass-get-secret "fake/source")
:to-equal "defuse-account-gad"))))