Function: auth-source-macos-keychain-search

auth-source-macos-keychain-search is a byte-compiled function defined in auth-source.el.gz.

Signature

(auth-source-macos-keychain-search &rest SPEC &key BACKEND CREATE DELETE TYPE MAX &allow-other-keys)

Documentation

Search the macOS Keychain; spec is like auth-source.

All search keys must match exactly. If you need substring matching, do a wider search and narrow it down yourself.

You'll get back all the properties of the token as a plist.

The :type key is either macos-keychain-internet or macos-keychain-generic.

For the internet keychain type, the :label key searches the item's labels ("-l LABEL" passed to "/usr/bin/security"). Similarly, :host maps to "-s HOST", :user maps to "-a USER", and :port maps to "-P PORT" or "-r PROT"
(note PROT has to be a 4-character string).

For the generic keychain type, the :label key searches the item's labels ("-l LABEL" passed to "/usr/bin/security"). Similarly, :host maps to "-c HOST" (the "creator" keychain field), :user maps to "-a USER", and :port maps to "-s PORT".

Here's an example that looks for the first item in the default generic macOS Keychain:

 (let ((auth-sources '(macos-keychain-generic)))
    (auth-source-search :max 1)

Here's another that looks for the first item in the internet macOS Keychain collection whose label is gnus:

 (let ((auth-sources '(macos-keychain-internet)))
    (auth-source-search :max 1 :label "gnus")

And this one looks for the first item in the internet keychain entries for git.gnus.org:

 (let ((auth-sources '(macos-keychain-internet")))
    (auth-source-search :max 1 :host "git.gnus.org"))

Source Code

;; Defined in /usr/src/emacs/lisp/auth-source.el.gz
;;; Backend specific parsing: Mac OS Keychain (using /usr/bin/security) backend

(cl-defun auth-source-macos-keychain-search (&rest spec
                                             &key backend create delete type max
                                             &allow-other-keys)
  "Search the macOS Keychain; spec is like `auth-source'.

All search keys must match exactly.  If you need substring
matching, do a wider search and narrow it down yourself.

You'll get back all the properties of the token as a plist.

The :type key is either `macos-keychain-internet' or
`macos-keychain-generic'.

For the internet keychain type, the :label key searches the
item's labels (\"-l LABEL\" passed to \"/usr/bin/security\").
Similarly, :host maps to \"-s HOST\", :user maps to \"-a USER\",
and :port maps to \"-P PORT\" or \"-r PROT\"
\(note PROT has to be a 4-character string).

For the generic keychain type, the :label key searches the item's
labels (\"-l LABEL\" passed to \"/usr/bin/security\").
Similarly, :host maps to \"-c HOST\" (the \"creator\" keychain
field), :user maps to \"-a USER\", and :port maps to \"-s PORT\".

Here's an example that looks for the first item in the default
generic macOS Keychain:

 (let ((auth-sources \\='(macos-keychain-generic)))
    (auth-source-search :max 1)

Here's another that looks for the first item in the internet
macOS Keychain collection whose label is `gnus':

 (let ((auth-sources \\='(macos-keychain-internet)))
    (auth-source-search :max 1 :label \"gnus\")

And this one looks for the first item in the internet keychain
entries for git.gnus.org:

 (let ((auth-sources \\='(macos-keychain-internet\")))
    (auth-source-search :max 1 :host \"git.gnus.org\"))"
  ;; TODO
  (cl-assert (not create) nil
          "The macOS Keychain auth-source backend doesn't support creation yet")
  ;; TODO
  ;; (macos-keychain-delete-item coll elt)
  (cl-assert (not delete) nil
          "The macOS Keychain auth-source backend doesn't support deletion yet")

  (let* ((coll (oref backend source))
         (max (or max 5000))     ; sanity check: default to stop at 5K
         ;; Filter out ignored keys from the spec
         (ignored-keys '(:create :delete :max :backend :label :host :port))
         ;; Build a search spec without the ignored keys
         ;; FIXME make this loop a function? it's used in at least 3 places
         (search-keys (cl-loop for i below (length spec) by 2
                               unless (memq (nth i spec) ignored-keys)
                               collect (nth i spec)))
         ;; If a search key value is nil or t (match anything), we skip it
         (search-spec (apply #'append (mapcar
                                      (lambda (k)
                                        (if (or (null (plist-get spec k))
                                                (eq t (plist-get spec k)))
                                            nil
                                          (list k (plist-get spec k))))
                                      search-keys)))
         ;; needed keys (always including host, login, port, and secret)
         (returned-keys (delete-dups (append
				      '(:host :login :port :secret)
				      search-keys)))
         ;; Extract host, port and user from spec
         (hosts (plist-get spec :host))
         (hosts (if (consp hosts) hosts `(,hosts)))
         (ports (plist-get spec :port))
         (ports (if (consp ports) ports `(,ports)))
         (users (plist-get spec :user))
         (users (if (consp users) users `(,users)))
         ;; Loop through all combinations of host/port and pass each of these to
         ;; auth-source-macos-keychain-search-items.  Convert numeric port to
         ;; string (bug#68376).
         (items (catch 'match
                  (dolist (host hosts)
                    (dolist (port ports)
                      (when (numberp port) (setq port (number-to-string port)))
                      (dolist (user users)
                        (let ((items (apply
                                      #'auth-source-macos-keychain-search-items
                                      coll
                                      type
                                      max
                                      host port user
                                      search-spec)))
                          (when items
                            (throw 'match items))))))))

         ;; ensure each item has each key in `returned-keys'
         (items (mapcar (lambda (plist)
                          (append
                           (apply #'append
                                  (mapcar (lambda (req)
                                            (if (plist-get plist req)
                                                nil
                                              (list req nil)))
                                          returned-keys))
                           plist))
                        items)))
    items))