]> git.eshelyaron.com Git - emacs.git/commitdiff
Simplify erc-sasl's auth-source API
authorF. Jason Park <jp@neverwas.me>
Thu, 24 Nov 2022 05:31:19 +0000 (21:31 -0800)
committerAmin Bandali <bandali@gnu.org>
Tue, 29 Nov 2022 05:01:13 +0000 (00:01 -0500)
* doc/misc/erc.texi: Revise descriptions in SASL chapter to reflect
simplified auth-source options.

* lisp/erc/erc-sasl.el (erc-sasl-password,
erc-sasl-auth-source-function): Revise doc strings.
(erc-sasl-auth-source-password-as-host): New function to serve as
more useful choice for option `erc-sasl-auth-source-function'.
(erc-sasl--read-password): Promote auth-source to pole position, above
an explicit string and `:password'.

* test/lisp/erc/erc-sasl-tests.el (erc-sasl--read-password--basic):
Massage tests to conform to simplified `erc-sasl-password'
API.  (Bug#29108.)

doc/misc/erc.texi
lisp/erc/erc-sasl.el
test/lisp/erc/erc-sasl-tests.el

index 2835baa3d6b685fcff3580ee6d29d49e61bcd09c..a8d1dd782357bb578b2c871b0f7edb63f1bb9535 100644 (file)
@@ -1055,17 +1055,10 @@ borrowing that parameter for its own uses, thus allowing you to call
 @code{erc-tls} with @code{:password} set to your NickServ password.
 
 You can also set this to a nonemtpy string, and ERC will send that
-when needed, no questions asked.  If you instead give a non-@code{nil}
-symbol (other than @code{:password}), like @samp{Libera.Chat}, ERC
-will use it for the @code{:host} field in an auth-source query.
-Actually, the same goes for when this option is @code{nil} but an
-explicit session ID is already on file (@pxref{Network Identifier}).
-For all such queries, ERC specifies the resolved value of
-@code{erc-sasl-user} for the @code{:user} (@code{:login}) param.  Keep
-in mind that none of this matters unless
-@code{erc-sasl-auth-source-function} holds a function, and it's
-@code{nil} by default.  As a last resort, ERC will prompt you for
-input.
+when needed, no questions asked.  Or, if you'd rather use auth-source,
+set @code{erc-sasl-auth-source-function} to a function, and ERC will
+perform an auth-source query instead.  As last resort in all cases,
+ERC will prompt you for input.
 
 Lastly, if your mechanism is @code{ecdsa-nist256p-challenge}, this
 option should instead hold the file name of your key.
@@ -1075,7 +1068,23 @@ option should instead hold the file name of your key.
 This is nearly identical to the other ERC @samp{auth-source} function
 options (@pxref{ERC auth-source functions}) except that the default
 value here is @code{nil}, meaning you have to set it to something like
-@code{erc-auth-source-search} for queries to be performed.
+@code{erc-auth-source-search} for queries to be performed.  For
+convenience, this module provides the following as a possible value:
+
+@defun erc-sasl-auth-source-password-as-host &rest plist
+Setting @code{erc-sasl-auth-source-function} to this function tells
+ERC to use @code{erc-sasl-password} for the @code{:host} field when
+querying auth-source, even if its value is the default
+@code{:password}, in which case ERC knows to ``resolve'' it to
+@code{erc-session-password} and use that as long as it's
+non-@code{nil}.  Otherwise, ERC just defers to
+@code{erc-auth-source-search} to determine the @code{:host}, along
+with everything else.
+@end defun
+
+As long as this option specifies a function, ERC will pass it the
+``resolved'' value of @code{erc-sasl-user} for the auth-source
+@code{:user} param.
 @end defopt
 
 @defopt erc-sasl-authzid
@@ -1143,10 +1152,11 @@ machine Example.Net login aph-bot password sesame
        (erc-tls :server "irc.libera.chat" :port 6697
                 :client-certificate t)))
     ('example
-     (let ((erc-sasl-auth-source-function #'erc-auth-source-search)
-           (erc-sasl-password 'Example.Net))
+     (let ((erc-sasl-auth-source-function
+            #'erc-sasl-auth-source-password-as-host))
        (erc-tls :server "irc.example.net" :port 6697
-                :user "alyssa")))))
+                :user "alyssa"
+                :password "Example.Net")))))
 @end lisp
 
 You've started storing your credentials with auth-source and have
index 5ee7169de5f468bc52cfbf651d128777b7e6baff..5b2c93988af5d0fedec270f74fed9e1927767ac5 100644 (file)
@@ -77,15 +77,14 @@ version is used."
 
 (defcustom erc-sasl-password :password
   "Optional account password to send when authenticating.
-When the value is a string, ERC will use it unconditionally for
-most mechanisms.  Likewise with `:password', except ERC will
-instead use the \"session password\" on file, which often
-originates from the entry-point commands `erc' or `erc-tls'.
-Otherwise, when `erc-sasl-auth-source-function' is a function,
-ERC will attempt an auth-source query, possibly using a non-nil
-symbol for the suggested `:host' parameter if set as this
-option's value or passed as an `:id' to `erc-tls'.  Failing that,
-ERC will prompt for input.
+When `erc-sasl-auth-source-function' is a function, ERC will
+attempt an auth-source query and prompt for input if it fails.
+Otherwise, when the value is a nonempty string, ERC will use it
+unconditionally for most mechanisms.  Likewise with `:password',
+except ERC will instead use the \"session password\" on file, if
+any, which often originates from the entry-point commands `erc'
+or `erc-tls'.  As with auth-source, ERC will prompt for input as
+a fallback.
 
 Note that, with `:password', ERC will forgo sending a traditional
 server password via the IRC \"PASS\" command.  Also, when
@@ -95,15 +94,18 @@ option should hold the file name of the key."
 
 (defcustom erc-sasl-auth-source-function nil
   "Function to query auth-source for an SASL password.
-Called with keyword params known to `auth-source-search', which
-includes `erc-sasl-user' for the `:user' field and
-`erc-sasl-password' for the `:host' field, when the latter option
-is a non-nil, non-keyword symbol.  In return, ERC expects a
-string to send as the SASL password, or nil, to move on to the
-next approach, as described in the doc string for the option
-`erc-sasl-password'.  See info node `(erc) Connecting' for
-details on ERC's auth-source integration."
-  :type '(choice (function-item erc-auth-source-search)
+If provided, this function should expect to be called with any
+number of keyword params known to `auth-source-search', even
+though ERC itself only specifies `:user' paired with a
+\"resolved\" `erc-sasl-user' value.  When calling this function,
+ERC binds all options defined in this library, such as
+`erc-sasl-password', to their values from entry-point invocation.
+In return, ERC expects a string to send as the SASL password, or
+nil, in which case, ERC will prompt the for input.  See info
+node `(erc) Connecting' for details on ERC's auth-source
+integration."
+  :type '(choice (function-item erc-sasl-auth-source-password-as-host)
+                 (function-item erc-auth-source-search)
                  (const nil)
                  function))
 
@@ -130,20 +132,35 @@ details on ERC's auth-source integration."
     (:nick (erc-downcase (erc-current-nick)))
     (v v)))
 
+(defun erc-sasl-auth-source-password-as-host (&rest plist)
+  "Call `erc-auth-source-search' with `erc-sasl-password' as `:host'.
+But only do so when it's a string or a non-nil symbol, unless
+that symbol is `:password', in which case, use a non-nil
+`erc-session-password' instead.  Otherwise, just defer to
+`erc-auth-source-search' to pick a suitable `:host'.  Expect
+PLIST to contain keyword params known to `auth-source-search'."
+  (when erc-sasl-password
+    (when-let ((host (if (eq :password erc-sasl-password)
+                         (and (not (functionp erc-session-password))
+                              erc-session-password)
+                       erc-sasl-password)))
+      (setq plist `(,@plist :host ,(format "%s" host)))))
+  (apply #'erc-auth-source-search plist))
+
 (defun erc-sasl--read-password (prompt)
   "Return configured option or server password.
-PROMPT is passed to `read-passwd' if necessary."
-  (if-let
-      ((found (pcase (alist-get 'password erc-sasl--options)
-                (:password erc-session-password)
-                ((and (pred stringp) v) (unless (string-empty-p v) v))
-                ((and (let fn (alist-get 'authfn erc-sasl--options))
-                      (guard fn) v
-                      (let host
-                        (or v (erc-networks--id-given erc-networks--id))))
-                 (apply fn
-                        :user (erc-sasl--get-user)
-                        (and host (list :host (symbol-name host))))))))
+If necessary, pass PROMPT to `read-passwd'."
+  (if-let ((found (pcase (alist-get 'password erc-sasl--options)
+                    ((guard (alist-get 'authfn erc-sasl--options))
+                     (let-alist erc-sasl--options
+                       (let ((erc-sasl-user .user)
+                             (erc-sasl-password .password)
+                             (erc-sasl-mechanism .mechanism)
+                             (erc-sasl-authzid .authzid)
+                             (erc-sasl-auth-source-function .authfn))
+                         (funcall .authfn :user (erc-sasl--get-user)))))
+                    (:password erc-session-password)
+                    ((and (pred stringp) v) (unless (string-empty-p v) v)))))
       (copy-sequence (erc--unfun found))
     (read-passwd prompt)))
 
index 3e6828ff644a17170624959dff96946c1688b8ab..0e5ea60e5f01b8b85d1e9f1eca1170ec939d86e3 100644 (file)
@@ -57,6 +57,8 @@
                          (erc-sasl--read-password "pwd:"))
                        "baz")))))
 
+;; This mainly tests `erc-sasl-auth-source-password-as-host'.
+
 (ert-deftest erc-sasl--read-password--auth-source ()
   (ert-with-temp-file netrc-file
     :text (string-join
            (erc-session-server "irc.gnu.org")
            (erc-session-port 6697)
            (erc-networks--id (erc-networks--id-create nil))
-           calls
-           (fn (lambda (&rest r)
-                 (push r calls)
-                 (apply #'erc-auth-source-search r)))
            erc-server-announced-name ; too early
-           auth-source-do-cache)
+           auth-source-do-cache
+           ;;
+           (fn #'erc-sasl-auth-source-password-as-host)
+           calls)
+
+      (advice-add 'erc-auth-source-search :before
+                  (lambda (&rest r) (push r calls))
+                  '((name . erc-sasl--read-password--auth-source)))
 
       (ert-info ("Symbol as password specifies machine")
         (let ((erc-sasl--options
-               `((user . "bob") (password . FSF.chat) (authfn . ,fn)))
-              (erc-networks--id (make-erc-networks--id)))
+               `((user . "bob") (password . FSF.chat) (authfn . ,fn))))
           (should (string= (erc-sasl--read-password nil) "sesame"))
           (should (equal (pop calls) '(:user "bob" :host "FSF.chat")))))
 
-      (ert-info ("ID for :host and `erc-session-username' for :user") ; *1
+      (ert-info (":password as password resolved to machine")
+        (let ((erc-session-password "FSF.chat")
+              (erc-sasl--options
+               `((user . "bob") (password . :password) (authfn . ,fn))))
+          (should (string= (erc-sasl--read-password nil) "sesame"))
+          (should (equal (pop calls) '(:user "bob" :host "FSF.chat")))))
+
+      (ert-info (":user resolved to `erc-session-username'") ; *1
         (let ((erc-session-username "bob")
               (erc-sasl--options `((user . :user) (password) (authfn . ,fn)))
               (erc-networks--id (erc-networks--id-create 'GNU/chat)))
           (should (string= (erc-sasl--read-password nil) "spam"))
-          (should (equal (pop calls) '(:user "bob" :host "GNU/chat")))))
+          (should (equal (pop calls) '(:user "bob")))))
 
-      (ert-info ("ID for :host and current nick for :user") ; *1
+      (ert-info (":user resolved to current nick") ; *1
         (let ((erc-server-current-nick "bob")
               (erc-sasl--options `((user . :nick) (password) (authfn . ,fn)))
               (erc-networks--id (erc-networks--id-create 'GNU/chat)))
           (should (string= (erc-sasl--read-password nil) "spam"))
-          (should (equal (pop calls) '(:user "bob" :host "GNU/chat")))))
+          (should (equal (pop calls) '(:user "bob")))))
 
       (ert-info ("Symbol as password, entry lacks user field")
         (let ((erc-server-current-nick "fake")
                `((user . :nick) (password . MyHost) (authfn . ,fn)))
               (erc-networks--id (erc-networks--id-create 'GNU/chat)))
           (should (string= (erc-sasl--read-password nil) "123"))
-          (should (equal (pop calls) '(:user "fake" :host "MyHost"))))))))
+          (should (equal (pop calls) '(:user "fake" :host "MyHost")))))
+
+      (advice-remove 'erc-auth-source-search
+                     'erc-sasl--read-password--auth-source))))
 
 (ert-deftest erc-sasl-create-client--plain ()
   (let* ((erc-session-password "password123")