aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/auth-source-pass.el112
1 files changed, 111 insertions, 1 deletions
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index 0955e2ed07e..dc274843e10 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -55,13 +55,27 @@
55 :type 'string 55 :type 'string
56 :version "27.1") 56 :version "27.1")
57 57
58(defcustom auth-source-pass-extra-query-keywords t
59 "Whether to consider additional keywords when performing a query.
60Specifically, when the value is t, recognize the `:max' and
61`:require' keywords and accept lists of query parameters for
62certain keywords, such as `:host' and `:user'. Also, wrap all
63returned secrets in a function and forgo any further results
64filtering unless given an applicable `:require' argument. When
65this option is nil, do none of that, and enact the narrowing
66behavior described toward the bottom of the Info node `(auth) The
67Unix password store'."
68 :type 'boolean
69 :version "29.1")
70
58(cl-defun auth-source-pass-search (&rest spec 71(cl-defun auth-source-pass-search (&rest spec
59 &key backend type host user port 72 &key backend type host user port
73 require max
60 &allow-other-keys) 74 &allow-other-keys)
61 "Given some search query, return matching credentials. 75 "Given some search query, return matching credentials.
62 76
63See `auth-source-search' for details on the parameters SPEC, BACKEND, TYPE, 77See `auth-source-search' for details on the parameters SPEC, BACKEND, TYPE,
64HOST, USER and PORT." 78HOST, USER, PORT, REQUIRE, and MAX."
65 (cl-assert (or (null type) (eq type (oref backend type))) 79 (cl-assert (or (null type) (eq type (oref backend type)))
66 t "Invalid password-store search: %s %s") 80 t "Invalid password-store search: %s %s")
67 (cond ((eq host t) 81 (cond ((eq host t)
@@ -70,6 +84,8 @@ HOST, USER and PORT."
70 ((null host) 84 ((null host)
71 ;; Do not build a result, as none will match when HOST is nil 85 ;; Do not build a result, as none will match when HOST is nil
72 nil) 86 nil)
87 (auth-source-pass-extra-query-keywords
88 (auth-source-pass--build-result-many host port user require max))
73 (t 89 (t
74 (when-let ((result (auth-source-pass--build-result host port user))) 90 (when-let ((result (auth-source-pass--build-result host port user)))
75 (list result))))) 91 (list result)))))
@@ -89,6 +105,39 @@ HOSTS can be a string or a list of strings."
89 (seq-subseq retval 0 -2)) ;; remove password 105 (seq-subseq retval 0 -2)) ;; remove password
90 retval)))) 106 retval))))
91 107
108(defvar auth-source-pass--match-regexp nil)
109
110(defun auth-source-pass--match-regexp (s)
111 (rx-to-string ; autoloaded
112 `(: (or bot "/")
113 (or (: (? (group-n 20 (+ (not (in ?\ ?/ ?@ ,s)))) "@")
114 (group-n 10 (+ (not (in ?\ ?/ ?@ ,s))))
115 (? ,s (group-n 30 (+ (not (in ?\ ?/ ,s))))))
116 (: (group-n 11 (+ (not (in ?\ ?/ ?@ ,s))))
117 (? ,s (group-n 31 (+ (not (in ?\ ?/ ,s)))))
118 (? "/" (group-n 21 (+ (not (in ?\ ?/ ,s)))))))
119 eot)
120 'no-group))
121
122(defun auth-source-pass--build-result-many (hosts ports users require max)
123 "Return multiple `auth-source-pass--build-result' values."
124 (unless (listp hosts) (setq hosts (list hosts)))
125 (unless (listp users) (setq users (list users)))
126 (unless (listp ports) (setq ports (list ports)))
127 (let* ((auth-source-pass--match-regexp (auth-source-pass--match-regexp
128 auth-source-pass-port-separator))
129 (rv (auth-source-pass--find-match-many hosts users ports
130 require (or max 1))))
131 (when auth-source-debug
132 (auth-source-pass--do-debug "final result: %S" rv))
133 (let (out)
134 (dolist (e rv out)
135 (when-let* ((s (plist-get e :secret)) ; not captured by closure in 29.1
136 (v (auth-source--obfuscate s)))
137 (setf (plist-get e :secret)
138 (lambda () (auth-source--deobfuscate v))))
139 (push e out)))))
140
92;;;###autoload 141;;;###autoload
93(defun auth-source-pass-enable () 142(defun auth-source-pass-enable ()
94 "Enable auth-source-password-store." 143 "Enable auth-source-password-store."
@@ -206,6 +255,67 @@ HOSTS can be a string or a list of strings."
206 hosts 255 hosts
207 (list hosts)))) 256 (list hosts))))
208 257
258(defun auth-source-pass--retrieve-parsed (seen path port-number-p)
259 (when (string-match auth-source-pass--match-regexp path)
260 (puthash path
261 `( :host ,(or (match-string 10 path) (match-string 11 path))
262 ,@(if-let* ((tr (match-string 21 path)))
263 (list :user tr :suffix t)
264 (list :user (match-string 20 path)))
265 :port ,(and-let* ((p (or (match-string 30 path)
266 (match-string 31 path)))
267 (n (string-to-number p)))
268 (if (or (zerop n) (not port-number-p))
269 (format "%s" p)
270 n)))
271 seen)))
272
273(defun auth-source-pass--match-parts (parts key value require)
274 (let ((mv (plist-get parts key)))
275 (if (memq key require)
276 (and value (equal mv value))
277 (or (not value) (not mv) (equal mv value)))))
278
279(defun auth-source-pass--find-match-many (hosts users ports require max)
280 "Return plists for valid combinations of HOSTS, USERS, PORTS."
281 (let ((seen (make-hash-table :test #'equal))
282 (entries (auth-source-pass-entries))
283 out suffixed suffixedp)
284 (catch 'done
285 (dolist (host hosts out)
286 (pcase-let ((`(,_ ,u ,p) (auth-source-pass--disambiguate host)))
287 (unless (or (not (equal "443" p)) (string-prefix-p "https://" host))
288 (setq p nil))
289 (dolist (user (or users (list u)))
290 (dolist (port (or ports (list p)))
291 (dolist (e entries)
292 (when-let*
293 ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed
294 seen e (integerp port))))
295 ((equal host (plist-get m :host)))
296 ((auth-source-pass--match-parts m :port port require))
297 ((auth-source-pass--match-parts m :user user require))
298 (parsed (auth-source-pass-parse-entry e))
299 ;; For now, ignore body-content pairs, if any,
300 ;; from `auth-source-pass--parse-data'.
301 (secret (or (auth-source-pass--get-attr 'secret parsed)
302 (not (memq :secret require)))))
303 (push
304 `( :host ,host ; prefer user-provided :host over h
305 ,@(and-let* ((u (plist-get m :user))) (list :user u))
306 ,@(and-let* ((p (plist-get m :port))) (list :port p))
307 ,@(and secret (not (eq secret t)) (list :secret secret)))
308 (if (setq suffixedp (plist-get m :suffix)) suffixed out))
309 (unless suffixedp
310 (when (or (zerop (cl-decf max))
311 (null (setq entries (delete e entries))))
312 (throw 'done out)))))
313 (setq suffixed (nreverse suffixed))
314 (while suffixed
315 (push (pop suffixed) out)
316 (when (zerop (cl-decf max))
317 (throw 'done out))))))))))
318
209(defun auth-source-pass--disambiguate (host &optional user port) 319(defun auth-source-pass--disambiguate (host &optional user port)
210 "Return (HOST USER PORT) after disambiguation. 320 "Return (HOST USER PORT) after disambiguation.
211Disambiguate between having user provided inside HOST (e.g., 321Disambiguate between having user provided inside HOST (e.g.,