-
Notifications
You must be signed in to change notification settings - Fork 4
/
helm-pass.el
165 lines (139 loc) · 5.15 KB
/
helm-pass.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
;;; helm-pass.el --- helm interface of pass, the standard Unix password manager -*- lexical-binding: t; -*-
;; Copyright (C) 2016--2018 J. Alexander Branham
;; Copyright (C) 2019 Pierre Neidhardt
;; Author: J. Alexander Branham <[email protected]>
;; Maintainer: Pierre Neidhardt <[email protected]>
;; URL: https://github.com/emacs-helm/helm-pass
;; Version: 0.4
;; Package-Requires: ((emacs "25") (helm "0") (password-store "0") (auth-source-pass "4.0.0"))
;; This file is not part of GNU Emacs.
;;; License:
;;
;; 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.
;;
;; 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:
;;
;; Emacs Helm interface for pass, the standard Unix password manager
;;
;; Users of helm-pass may also be interested in functionality provided by other
;; Emacs packages dealing with pass:
;;
;; - password-store.el (which helm-pass relies on):
;; https://git.zx2c4.com/password-store/tree/contrib/emacs/password-store.el
;;
;; - pass.el (a major mode for pass): https://github.com/NicolasPetton/pass
;;
;; - auth-source-pass.el (integration of Emacs' auth-source with pass, included
;; in Emacs 26+): https://github.com/DamienCassou/auth-password-store
;; Usage:
;;
;; (require 'helm-pass)
;; M-x helm-pass
;;; Code:
(require 'helm)
(require 'password-store)
(require 'auth-source-pass)
(require 'thingatpt)
(require 'seq)
(defvar exwm-title)
(declare-function eww-current-url "eww")
(defgroup helm-pass nil
"Emacs helm interface for helm-pass"
:group 'helm)
(defun helm-pass-get-fields (entry)
(mapcar 'car (auth-source-pass-parse-entry entry)))
(defun helm-pass-get-field (key entry)
"Get the value associated with KEY for ENTRY.
Does not clear it from clipboard."
(if (string-equal key "secret")
(setq key 'secret))
(let ((field (auth-source-pass-get key entry)))
(if field
(progn (password-store-clear)
(kill-new field))
(message (format "%s has no field: %s" entry field)))))
(defcustom helm-pass-actions
'(("Copy password to clipboard" . password-store-copy)
("Copy field to clipboard" . helm-pass-fields)
("Edit entry" . password-store-edit)
("Browse url of entry" . password-store-url))
"List of actions for `helm-pass'."
:group 'helm-pass
:type '(alist :key-type string :value-type function))
(defvar helm-pass-source-pass
(helm-build-sync-source "Password File"
:candidates #'password-store-list
:action helm-pass-actions))
(defun helm-pass-source-pass-fields (entry)
(helm-build-sync-source "Password Fields"
:candidates (helm-pass-get-fields entry)
:action (lambda (x) (helm-pass-get-field x entry))))
(defun helm-pass-find-url-in-string (string)
"Return URL from STRING."
(with-temp-buffer
(insert string)
(goto-char (point-min))
(while (and (not (eobp))
(not (thing-at-point-url-at-point)))
(forward-word))
(thing-at-point-url-at-point)))
(defvar helm-pass-domain-regexp
(rx "//"
(group
(* (not (any "/")))
"."
(* (not (any "." "/"))))
"/"))
(defun helm-pass-get-domain (url)
"Return the various domain elements or URL as a list of strings."
(when url
(string-match helm-pass-domain-regexp url)
(split-string (match-string 1 url) "\\.")))
(defun helm-pass-get-subdomain (domain &optional count)
"Return the last COUNT elements of DOMAIN as a dot-separated string.
COUNT defaults to 2.
For instance, (\"foo\" \"example\" \"org\") results in \"example.org\".
If domain does not have enough elements, return nil."
(setq count (or count 2))
(when (>= (length domain) count)
(mapconcat #'identity (seq-drop domain (- (length domain) count)) ".")))
(defun helm-pass-get-input-from-eww ()
"Get default prompt from EWW."
(let* ((domain (helm-pass-get-domain (eww-current-url))))
(helm-pass-get-subdomain domain)))
(defun helm-pass-get-input-from-exwm ()
"Get default prompt from the current EXWM window."
(when exwm-title
(let* ((url (helm-pass-find-url-in-string exwm-title))
(domain (helm-pass-get-domain url)))
(helm-pass-get-subdomain domain))))
(defun helm-pass-get-input ()
"Get default prompt from the current mode."
(cond
((derived-mode-p 'eww-mode)
(helm-pass-get-input-from-eww))
((derived-mode-p 'exwm-mode)
(helm-pass-get-input-from-exwm))))
;;;###autoload
(defun helm-pass ()
"Helm interface for pass."
(interactive)
(helm :sources 'helm-pass-source-pass
:input (helm-pass-get-input)
:buffer "*helm-pass*"))
(defun helm-pass-fields (arg)
(helm :sources (helm-pass-source-pass-fields arg)
:buffer "*helm-pass-fields*"))
(provide 'helm-pass)
;;; helm-pass.el ends here