From ba6fae5c2851e2926e20e21c8dc962977c94987a Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Sun, 13 Nov 2022 22:38:13 -0800 Subject: [PATCH 0/5] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (5): Add GS2 authorization to sasl-scram-rfc Don't set erc-networks--id until network is known Support local ERC modules in erc-mode buffers Call erc-login indirectly via new generic wrapper Add non-IRCv3 SASL module to ERC doc/misc/erc.texi | 148 +++++- etc/ERC-NEWS | 21 +- lisp/erc/erc-backend.el | 15 +- lisp/erc/erc-common.el | 56 ++- lisp/erc/erc-compat.el | 116 +++++ lisp/erc/erc-goodies.el | 1 + lisp/erc/erc-networks.el | 39 +- lisp/erc/erc-sasl.el | 433 ++++++++++++++++++ lisp/erc/erc.el | 85 ++-- lisp/net/sasl-scram-rfc.el | 21 +- test/lisp/erc/erc-sasl-tests.el | 319 +++++++++++++ test/lisp/erc/erc-scenarios-sasl.el | 208 +++++++++ test/lisp/erc/erc-tests.el | 63 +++ test/lisp/erc/resources/sasl/external.eld | 33 ++ test/lisp/erc/resources/sasl/plain-failed.eld | 16 + test/lisp/erc/resources/sasl/plain.eld | 39 ++ test/lisp/erc/resources/sasl/scram-sha-1.eld | 47 ++ .../lisp/erc/resources/sasl/scram-sha-256.eld | 47 ++ 18 files changed, 1621 insertions(+), 86 deletions(-) create mode 100644 lisp/erc/erc-sasl.el create mode 100644 test/lisp/erc/erc-sasl-tests.el create mode 100644 test/lisp/erc/erc-scenarios-sasl.el create mode 100644 test/lisp/erc/resources/sasl/external.eld create mode 100644 test/lisp/erc/resources/sasl/plain-failed.eld create mode 100644 test/lisp/erc/resources/sasl/plain.eld create mode 100644 test/lisp/erc/resources/sasl/scram-sha-1.eld create mode 100644 test/lisp/erc/resources/sasl/scram-sha-256.eld Interdiff: diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 79f8c92719..8eb33c8e80 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -390,8 +390,15 @@ Modules There is a spiffy customize interface, which may be reached by typing @kbd{M-x customize-option @key{RET} erc-modules @key{RET}}. -Alternatively, set @code{erc-modules} manually and then call -@code{erc-update-modules}. +Alternatively, set @code{erc-modules} manually, and ERC will load them +and run their setup code during buffer initialization. Third-party +code may need to call the function @code{erc-update-modules} +explicitly, although this is typically unnecessary. + +All modules operate as minor modes under the hood, and some newer ones +are defined as buffer-local. For everyday use, the only practical +difference is that local modules can only be enabled in ERC buffers, +and their toggle commands never mutate @code{erc-modules}. The following is a list of available modules. @@ -1026,7 +1033,7 @@ SASL Otherwise, if you set this option to @code{nil} (or the empty string) or if an auth-source lookup has failed, ERC will try a non-@code{nil} -``server password'', likely whatever you gave as the @var{password} +``server password,'' likely whatever you gave as the @var{password} argument to @code{erc-tls}. This fallback behavior may change, however, so please don't rely on it. As a last resort, ERC will prompt you for input. diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 5cabb9b015..f5b14376ad 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -48,10 +48,9 @@ hell. For some, auth-source may provide a workaround in the form of nonstandard server passwords. See the "Connection" node in the manual under the subheading "Password". -If you require SASL immediately, please participate in ERC development -by volunteering to try (and give feedback on) edge features, one of -which is SASL. All known external offerings, past and present, are -valiant efforts whose use is nevertheless discouraged. +** Rudimentary SASL support has arrived. +A new module, 'erc-sasl', now ships with ERC 5.5. See the SASL +section in the manual for details. ** Username argument for entry-point commands. Commands 'erc' and 'erc-tls' now accept a ':user' keyword argument, @@ -97,6 +96,20 @@ messages during periods of heavy traffic no longer disappear. Although rare, server passwords containing white space are now handled correctly. +** Local modules and ERC-mode hooks are more useful. +The 'local-p' parameter of 'define-erc-module' now affects more than +the scope of a module's minor-mode. This currently has little direct +impact on the user experience, but third-party packages may wish to +take note. + +More importantly, the function 'erc-update-modules' now supports an +optional argument to defer the enabling of local modules and instead +return their mode-activation commands. 'erc-open' leverages this new +functionality to delay their activation, as well as that of all +'erc-mode-hook' members, until most of ERC's mode-related variables +have been initialized. This does not include connection-specific +variables defined in erc-backend, however. + ** Miscellaneous behavioral changes in the library API. A number of core macros and other definitions have been moved to a new file called erc-common.el. This was done to further lessen the diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index a300cfc4fa..e5fabdc67f 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -173,17 +173,17 @@ define-erc-module name) (interactive) ,@(unless local-p `((cl-pushnew ',mod erc-modules))) - ,@(macroexp-unprogn - `(,@(if local-p '(when (eq major-mode 'erc-mode)) '(progn)) - (setq ,mode t) - ,@enable-body))) + ,@(if local-p + `((when (setq ,mode (and (derived-mode-p 'erc-mode) t)) + ,@enable-body)) + `((setq ,mode t) ,@enable-body))) (defun ,disable () ,(format "Disable ERC %S mode." name) (interactive) ,@(unless local-p `((setq erc-modules (delq ',mod erc-modules)))) ,@(macroexp-unprogn - `(,@(if local-p `(when ,mode) '(progn)) + `(,@(if local-p '(when (derived-mode-p 'erc-mode)) '(progn)) (setq ,mode nil) ,@disable-body))) ,(when (and alias (not (eq name alias))) diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index 6d4ef21383..d4a2e312be 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -272,7 +272,7 @@ erc-compat--with-memoization `(cl--generic-with-memoization ,table ,@forms)) (t `(progn ,@forms)))) -(defun erc-compat--local-minor-modes () +(defun erc-compat--local-module-modes () (delq nil (if (boundp 'local-minor-modes) (mapcar (lambda (m) diff --git a/lisp/erc/erc-sasl.el b/lisp/erc/erc-sasl.el index ac2646051c..a9d7ed235d 100644 --- a/lisp/erc/erc-sasl.el +++ b/lisp/erc/erc-sasl.el @@ -223,17 +223,18 @@ erc-sasl--create-client (let ((sasl-mechanism-alist (copy-sequence sasl-mechanism-alist)) (sasl-mechanisms sasl-mechanisms) (name (upcase (symbol-name mechanism))) - (feature (intern (concat "erc-sasl-" (symbol-name mechanism)))) + (feature (intern-soft (concat "erc-sasl-" (symbol-name mechanism)))) client) - (setf (alist-get name sasl-mechanism-alist nil nil #'equal) `(,feature)) - (cl-pushnew name sasl-mechanisms :test #'equal) - (setq client (sasl-make-client (sasl-find-mechanism `(,name)) - (or (alist-get 'user erc-sasl--options) - (erc-downcase (erc-current-nick))) - "N/A" "N/A")) - (sasl-client-set-property client 'authenticator-name - (alist-get 'authzid erc-sasl--options)) - client)) + (when feature + (setf (alist-get name sasl-mechanism-alist nil nil #'equal) `(,feature)) + (cl-pushnew name sasl-mechanisms :test #'equal) + (setq client (sasl-make-client (sasl-find-mechanism `(,name)) + (or (alist-get 'user erc-sasl--options) + (erc-downcase (erc-current-nick))) + "N/A" "N/A")) + (sasl-client-set-property client 'authenticator-name + (alist-get 'authzid erc-sasl--options)) + client))) (cl-defmethod erc-sasl--create-client ((_m (eql plain))) "Create and return a new PLAIN client object." @@ -296,7 +297,9 @@ erc-sasl--init (defun erc-sasl--on-connection-established (&rest _) (setf (alist-get erc-networks--id erc-sasl--session-options nil nil #'erc-networks--id-equal-p) - erc-sasl--options)) + erc-sasl--options + ;; + erc-sasl--options nil)) (defun erc-sasl--mechanism-offered-p (offered) "Return non-nil when OFFERED appears among a list of mechanisms." @@ -318,7 +321,8 @@ erc-sasl--authenticate-handler (when (string= "+" response) (setq response "")) (setf response (base64-decode-string - (concat (erc-sasl--state-pending erc-sasl--state) response)) + (concat (erc-sasl--state-pending erc-sasl--state) + response)) (erc-sasl--state-pending erc-sasl--state) nil) ;; The server is done sending, so our turn (let ((client (erc-sasl--state-client erc-sasl--state)) @@ -357,11 +361,14 @@ sasl (let* ((mech (alist-get 'mechanism erc-sasl--options)) (client (erc-sasl--create-client mech))) (unless client - (erc-display-error-notice nil (format "Unknown mechanism: %s" mech)) - (erc-error "Unknown mechanism: %s" mech)) + (erc-display-error-notice + nil (format "Unknown SASL mechanism: %s" mech)) + (erc-error "Unknown SASL mechanism: %s" mech)) (setf (erc-sasl--state-client erc-sasl--state) client)))) ((remove-hook 'erc-server-AUTHENTICATE-functions #'erc-sasl--authenticate-handler t) + (setf (alist-get erc-networks--id erc-sasl--session-options nil t) nil) + (kill-local-variable 'erc-sasl--state) (kill-local-variable 'erc-sasl--options)) 'local) @@ -410,11 +417,13 @@ erc-sasl--destroy (cl-defmethod erc--register-connection (&context (erc-sasl-mode (eql t))) "Send speculative/pipelined CAP and AUTHENTICATE and hope for the best." - (erc-server-send "CAP REQ :sasl") - (erc-login) - (let* ((c (erc-sasl--state-client erc-sasl--state)) - (m (sasl-mechanism-name (sasl-client-mechanism c)))) - (erc-server-send (format "AUTHENTICATE %s" m)))) + (if-let* ((c (erc-sasl--state-client erc-sasl--state)) + (m (sasl-mechanism-name (sasl-client-mechanism c)))) + (progn + (erc-server-send "CAP REQ :sasl") + (erc-login) + (erc-server-send (format "AUTHENTICATE %s" m))) + (erc-sasl--destroy erc-server-process))) (provide 'erc-sasl) ;;; erc-sasl.el ends here diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index a703f903ec..c5989dbc7e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1871,7 +1871,7 @@ erc-update-modules introduced in ERC 5.5." (let ((local-modes (when (and defer-locals (derived-mode-p 'erc-mode)) - (erc-compat--local-minor-modes)))) + (erc-compat--local-module-modes)))) (dolist (module erc-modules (and defer-locals local-modes)) (require (or (alist-get module erc--modules-to-features) (intern (concat "erc-" (symbol-name module)))) -- 2.38.1