diff options
| author | Damien Cassou | 2019-05-14 05:50:59 +0200 |
|---|---|---|
| committer | Damien Cassou | 2019-06-24 09:15:41 +0200 |
| commit | 7022e3fde6bc577cc281bd8770fe5a41f7492b4f (patch) | |
| tree | 7c423e6931eb57a3a5d0bf7ec7c3153cbfbbf0a3 /lisp | |
| parent | 736f78bb1af0593d9b02f0a45a64b1422a6fcc12 (diff) | |
| download | emacs-7022e3fde6bc577cc281bd8770fe5a41f7492b4f.tar.gz emacs-7022e3fde6bc577cc281bd8770fe5a41f7492b4f.zip | |
Refactoring of auth-source-pass
* lisp/auth-source-pass.el (auth-source-pass--find-match): Refactor by
moving some code to auth-source-pass--disambiguate.
(auth-source-pass--disambiguate)
(auth-source-pass--entries-matching-suffix): New function.
(auth-source-pass--find-match-unambiguous)
(auth-source-pass--select-from-entries)
(auth-source-pass--entry-reducer): Refactor to simplify and improve
logging.
(auth-source-pass--matching-entries)
(auth-source-pass--accumulate-matches): Remove.
* test/lisp/auth-source-pass-tests.el: Complete rewrite to facilitate
maintenance.
(auth-source-pass--have-message-containing): Remove.
(auth-source-pass--have-message-matching)
(auth-source-pass--explain--have-message-matching)
(auth-source-pass--explain-match-entry-p)
(auth-source-pass--includes-sorted-entries)
(auth-source-pass--explain-includes-sorted-entries)
(auth-source-pass--explain-match-any-entry-p)
(auth-source-pass--matching-entries)
(auth-source-pass-match-entry-p)
(auth-source-pass-match-any-entry-p): New function.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/auth-source-pass.el | 108 |
1 files changed, 45 insertions, 63 deletions
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index af421645cbc..295bda507b0 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el | |||
| @@ -197,10 +197,17 @@ CONTENTS is the contents of a password-store formatted file." | |||
| 197 | 197 | ||
| 198 | Disambiguate between user provided inside HOST (e.g., user@server.com) and | 198 | Disambiguate between user provided inside HOST (e.g., user@server.com) and |
| 199 | inside USER by giving priority to USER. Same for PORT." | 199 | inside USER by giving priority to USER. Same for PORT." |
| 200 | (apply #'auth-source-pass--find-match-unambiguous (auth-source-pass--disambiguate host user port))) | ||
| 201 | |||
| 202 | (defun auth-source-pass--disambiguate (host &optional user port) | ||
| 203 | "Return (HOST USER PORT) after disambiguation. | ||
| 204 | Disambiguate between having user provided inside HOST (e.g., | ||
| 205 | user@server.com) and inside USER by giving priority to USER. | ||
| 206 | Same for PORT." | ||
| 200 | (let* ((url (url-generic-parse-url (if (string-match-p ".*://" host) | 207 | (let* ((url (url-generic-parse-url (if (string-match-p ".*://" host) |
| 201 | host | 208 | host |
| 202 | (format "https://%s" host))))) | 209 | (format "https://%s" host))))) |
| 203 | (auth-source-pass--find-match-unambiguous | 210 | (list |
| 204 | (or (url-host url) host) | 211 | (or (url-host url) host) |
| 205 | (or user (url-user url)) | 212 | (or user (url-user url)) |
| 206 | ;; url-port returns 443 (because of the https:// above) by default | 213 | ;; url-port returns 443 (because of the https:// above) by default |
| @@ -212,74 +219,49 @@ If many matches are found, return the first one. If no match is found, | |||
| 212 | return nil. | 219 | return nil. |
| 213 | 220 | ||
| 214 | HOSTNAME should not contain any username or port number." | 221 | HOSTNAME should not contain any username or port number." |
| 215 | (cl-reduce | 222 | (let ((all-entries (auth-source-pass-entries)) |
| 216 | (lambda (result entries) | 223 | (suffixes (auth-source-pass--generate-entry-suffixes hostname user port))) |
| 217 | (or result | 224 | (auth-source-pass--do-debug "searching for entries matching hostname=%S, user=%S, port=%S" |
| 218 | (pcase (length entries) | 225 | hostname (or user "") (or port "")) |
| 219 | (0 nil) | 226 | (auth-source-pass--do-debug "corresponding suffixes to search for: %S" suffixes) |
| 220 | (1 (auth-source-pass-parse-entry (car entries))) | 227 | (catch 'auth-source-pass-break |
| 221 | (_ (auth-source-pass--select-from-entries entries user))))) | 228 | (dolist (suffix suffixes) |
| 222 | (auth-source-pass--matching-entries hostname user port) | 229 | (let* ((matching-entries (auth-source-pass--entries-matching-suffix suffix all-entries)) |
| 223 | :initial-value nil)) | 230 | (best-entry-data (auth-source-pass--select-from-entries matching-entries user))) |
| 231 | (pcase (length matching-entries) | ||
| 232 | (0 (auth-source-pass--do-debug "found no entries matching %S" suffix)) | ||
| 233 | (1 (auth-source-pass--do-debug "found 1 entry matching %S: %S" | ||
| 234 | suffix | ||
| 235 | (car matching-entries))) | ||
| 236 | (_ (auth-source-pass--do-debug "found %s entries matching %S: %S" | ||
| 237 | (length matching-entries) | ||
| 238 | suffix | ||
| 239 | matching-entries))) | ||
| 240 | (when best-entry-data | ||
| 241 | (throw 'auth-source-pass-break best-entry-data))))))) | ||
| 224 | 242 | ||
| 225 | (defun auth-source-pass--select-from-entries (entries user) | 243 | (defun auth-source-pass--select-from-entries (entries user) |
| 226 | "Return best matching password-store entry data from ENTRIES. | 244 | "Return best matching password-store entry data from ENTRIES. |
| 227 | 245 | ||
| 228 | If USER is non nil, give precedence to entries containing a user field | 246 | If USER is non nil, give precedence to entries containing a user field |
| 229 | matching USER." | 247 | matching USER." |
| 230 | (cl-reduce | 248 | (let (fallback) |
| 231 | (lambda (result entry) | 249 | (catch 'auth-source-pass-break |
| 232 | (let ((entry-data (auth-source-pass-parse-entry entry))) | 250 | (dolist (entry entries fallback) |
| 233 | (cond ((equal (auth-source-pass--get-attr "user" result) user) | 251 | (let ((entry-data (auth-source-pass-parse-entry entry))) |
| 234 | result) | 252 | (when (and entry-data (not fallback)) |
| 235 | ((equal (auth-source-pass--get-attr "user" entry-data) user) | 253 | (setq fallback entry-data) |
| 236 | entry-data) | 254 | (when (or (not user) (equal (auth-source-pass--get-attr "user" entry-data) user)) |
| 237 | (t | 255 | (throw 'auth-source-pass-break entry-data)))))))) |
| 238 | result)))) | 256 | |
| 239 | entries | 257 | (defun auth-source-pass--entries-matching-suffix (suffix entries) |
| 240 | :initial-value (auth-source-pass-parse-entry (car entries)))) | 258 | "Return entries matching SUFFIX. |
| 241 | 259 | If ENTRIES is nil, use the result of calling `auth-source-pass-entries' instead." | |
| 242 | (defun auth-source-pass--matching-entries (hostname user port) | 260 | (cl-remove-if-not |
| 243 | "Return all matching password-store entries for HOSTNAME, USER, & PORT. | 261 | (lambda (entry) (string-match-p |
| 244 | 262 | (format "\\(^\\|/\\)%s$" (regexp-quote suffix)) | |
| 245 | The result is a list of lists of password-store entries, where | 263 | entry)) |
| 246 | each sublist contains entries that actually exist in the | 264 | (or entries (auth-source-pass-entries)))) |
| 247 | password-store matching one of the entry name formats that | ||
| 248 | auth-source-pass expects, most specific to least specific." | ||
| 249 | (let* ((entries-lists (mapcar | ||
| 250 | #'cdr | ||
| 251 | (auth-source-pass--accumulate-matches hostname user port))) | ||
| 252 | (entries (apply #'cl-concatenate (cons 'list entries-lists)))) | ||
| 253 | (if entries | ||
| 254 | (auth-source-pass--do-debug (format "found: %S" entries)) | ||
| 255 | (auth-source-pass--do-debug "no matches found")) | ||
| 256 | entries-lists)) | ||
| 257 | |||
| 258 | (defun auth-source-pass--accumulate-matches (hostname user port) | ||
| 259 | "Accumulate matching password-store entries into sublists. | ||
| 260 | |||
| 261 | Entries matching supported formats that combine HOSTNAME, USER, & | ||
| 262 | PORT are accumulated into sublists where the car of each sublist | ||
| 263 | is a regular expression for matching paths in the password-store | ||
| 264 | and the remainder is the list of matching entries." | ||
| 265 | (let ((suffix-match-lists | ||
| 266 | (mapcar (lambda (suffix) (list (format "\\(^\\|/\\)%s$" suffix))) | ||
| 267 | (auth-source-pass--generate-entry-suffixes hostname user port)))) | ||
| 268 | (cl-reduce #'auth-source-pass--entry-reducer | ||
| 269 | (auth-source-pass-entries) | ||
| 270 | :initial-value suffix-match-lists))) | ||
| 271 | |||
| 272 | (defun auth-source-pass--entry-reducer (match-lists entry) | ||
| 273 | "Match MATCH-LISTS sublists against ENTRY. | ||
| 274 | |||
| 275 | The result is a copy of match-lists with the entry added to the | ||
| 276 | end of any sublists for which the regular expression at the head | ||
| 277 | of the list matches the entry name." | ||
| 278 | (mapcar (lambda (match-list) | ||
| 279 | (if (string-match (car match-list) entry) | ||
| 280 | (append match-list (list entry)) | ||
| 281 | match-list)) | ||
| 282 | match-lists)) | ||
| 283 | 265 | ||
| 284 | (defun auth-source-pass--generate-entry-suffixes (hostname user port) | 266 | (defun auth-source-pass--generate-entry-suffixes (hostname user port) |
| 285 | "Return a list of possible entry path suffixes in the password-store. | 267 | "Return a list of possible entry path suffixes in the password-store. |