ERC: NickServ: Prompt for password last, overall simplifications (bug#46777)

When 'erc-prompt-for-nickserv-password' is non-nil, don't ignore the
other forms of identification.  Instead, process them first, and
prompt for the password last.  Separate concerns (determination of the
nick to use, of the password to use, and actual message sending).

Note that the user can be interactively prompted for a password on
reception of a NickServ request, as before (on
'erc-prompt-for-nickserv-password').

* lisp/erc/erc-services.el (erc-nickserv-identify): Make the password
argument optional (and don't prompt for it interactively).  Further,
now take the nick to use for identification (interactively, ask for
it, defaulting to the current one).  Move the actual message sending
into the new 'erc-nickserv-send-identify' function, and the password
prompting into 'erc-nickserv-get-password'.

(erc-nickserv-send-identify): New function containing the code for
sending the identify message to NickServ, given the nick and password.

(erc-nickserv-get-password): Try each password source in turn, in the
following order: 'erc-nickserv-passwords', auth-source (if
'erc-use-auth-source-for-nickserv-password' is non-nil), and in the
end prompt the user interactively (if
'erc-prompt-for-nickserv-password' is non-nil).  If one source returns
a string, the function returns it, or nil if the string is empty.

(erc-nickserv-call-identify-function): Declare obsolete, but retain
for backward compatibility.  Prefer invoking 'erc-nickserv-identify'
directly instead.

(erc-nickserv-identify-autodetect, erc-nickserv-identify-on-connect)
(erc-nickserv-identify-on-nick-change): Call 'erc-nickserv-identify'
directly ('erc-nickserv-call-identify-function' has been obsoleted).
For the last two functions, remove the redundant checks on the
NickServ identification flags (additionally, it is doubtful they have
any measurable impact on performance).

* etc/NEWS: Announce the change.

Co-authored-by: F. Jason Park <jp@neverwas.me>
This commit is contained in:
Olivier Certner 2021-02-05 15:34:50 +01:00 committed by Amin Bandali
parent f7ed946874
commit c6eb114a42
No known key found for this signature in database
GPG key ID: 8B44A0CDC7B956F2
2 changed files with 108 additions and 71 deletions

View file

@ -2632,13 +2632,22 @@ Interactively, 'C-u C-c C-o' triggers this new optional behavior.
** ERC
---
*** erc-services.el now supports NickServ passwords from auth-source.
*** NickServ passwords can now be retrieved from auth-source.
The 'erc-use-auth-source-for-nickserv-password' user option enables
querying auth-source for NickServ passwords. To enable this, add the
following to your init file:
(setq erc-prompt-for-nickserv-password nil
erc-use-auth-source-for-nickserv-password t)
(setq erc-use-auth-source-for-nickserv-password t)
---
*** NickServ identification now prompts for password last.
When 'erc-prompt-for-nickserv-password' is non-nil, the user used to
be unconditionally prompted interactively for a password, regardless
of the value of 'erc-nickserv-passwords', which was effectively
ignored (same for the new
'erc-use-auth-source-for-nickserv-password'). This limitation is now
lifted, and the user is interactively prompted last, after the other
identification methods have run.
---
*** The '/ignore' command will now ask for a timeout to stop ignoring the user.

View file

@ -169,9 +169,8 @@ You can also use \\[erc-nickserv-identify-mode] to change modes."
(defcustom erc-use-auth-source-for-nickserv-password nil
"Query auth-source for a password when identifiying to NickServ.
This option has an no effect if `erc-prompt-for-nickserv-password'
is non-nil, and passwords from `erc-nickserv-passwords' take
precedence."
Passwords from `erc-nickserv-passwords' take precedence. See
function `erc-nickserv-get-password'."
:version "28.1"
:type 'boolean)
@ -405,85 +404,114 @@ password for this nickname, otherwise try to send it automatically."
identify-regex
(string-match identify-regex msg))
(erc-log "NickServ IDENTIFY request detected")
(erc-nickserv-call-identify-function nick)
(erc-nickserv-identify nil nick)
nil))))
(defun erc-nickserv-identify-on-connect (_server nick)
"Identify to Nickserv after the connection to the server is established."
(unless (or (and (null erc-nickserv-passwords)
(null erc-prompt-for-nickserv-password)
(null erc-use-auth-source-for-nickserv-password))
(and (eq erc-nickserv-identify-mode 'both)
(erc-nickserv-alist-regexp (erc-network))))
(erc-nickserv-call-identify-function nick)))
(unless (and (eq erc-nickserv-identify-mode 'both)
(erc-nickserv-alist-regexp (erc-network)))
(erc-nickserv-identify nil nick)))
(defun erc-nickserv-identify-on-nick-change (nick _old-nick)
"Identify to Nickserv whenever your nick changes."
(unless (or (and (null erc-nickserv-passwords)
(null erc-prompt-for-nickserv-password)
(null erc-use-auth-source-for-nickserv-password))
(and (eq erc-nickserv-identify-mode 'both)
(erc-nickserv-alist-regexp (erc-network))))
(erc-nickserv-call-identify-function nick)))
(unless (and (eq erc-nickserv-identify-mode 'both)
(erc-nickserv-alist-regexp (erc-network)))
(erc-nickserv-identify nil nick)))
(defun erc-nickserv-get-password (nickname)
"Return the password for NICKNAME from configured sources.
(defun erc-nickserv-get-password (nick)
"Return the password for NICK from configured sources.
First, a password for NICK is looked up in
`erc-nickserv-passwords'. Then, it is looked up in auth-source
if `erc-use-auth-source-for-nickserv-password' is not nil.
Finally, interactively prompt the user, if
`erc-prompt-for-nickserv-password' is true.
It uses `erc-nickserv-passwords' and additionally auth-source
when `erc-use-auth-source-for-nickserv-password' is not nil."
(or
(when erc-nickserv-passwords
(cdr (assoc nickname
(nth 1 (assoc (erc-network)
erc-nickserv-passwords)))))
(when erc-use-auth-source-for-nickserv-password
(let* ((secret (nth 0 (auth-source-search
:max 1 :require '(:secret)
:host (erc-with-server-buffer erc-session-server)
:port (format ; ensure we have a string
"%s" (erc-with-server-buffer erc-session-port))
:user nickname))))
(when secret
(let ((passwd (plist-get secret :secret)))
(if (functionp passwd) (funcall passwd) passwd)))))))
(defun erc-nickserv-call-identify-function (nickname)
"Call `erc-nickserv-identify'.
Either call it interactively or run it with NICKNAME's password,
depending on the value of `erc-prompt-for-nickserv-password'."
(if erc-prompt-for-nickserv-password
(call-interactively 'erc-nickserv-identify)
(erc-nickserv-identify (erc-nickserv-get-password nickname))))
As soon as some source returns a password, the sequence of
lookups stops and this function returns it (or returns nil if it
is empty). Otherwise, no corresponding password was found, and
it returns nil."
(let (network server port)
;; Fill in local vars, switching to the server buffer once only
(erc-with-server-buffer
(setq network erc-network
server erc-session-server
port erc-session-port))
(let ((ret
(or
(when erc-nickserv-passwords
(cdr (assoc nick
(cl-second (assoc network
erc-nickserv-passwords)))))
(when erc-use-auth-source-for-nickserv-password
(let ((secret (cl-first (auth-source-search
:max 1 :require '(:secret)
:host server
;; Ensure a string for :port
:port (format "%s" port)
:user nick))))
(when secret
(let ((passwd (plist-get secret :secret)))
(if (functionp passwd) (funcall passwd) passwd)))))
(when erc-prompt-for-nickserv-password
(read-passwd
(format "NickServ password for %s on %s (RET to cancel): "
nick network))))))
(when (and ret (not (string= ret "")))
ret))))
(defvar erc-auto-discard-away)
;;;###autoload
(defun erc-nickserv-identify (password)
(defun erc-nickserv-send-identify (nick password)
"Send an \"identify <PASSWORD>\" message to NickServ.
When called interactively, read the password using `read-passwd'."
Returns t if the message could be sent, nil otherwise."
(let* ((erc-auto-discard-away nil)
(network (erc-network))
(nickserv-info (assoc network erc-nickserv-alist))
(nickserv (or (erc-nickserv-alist-nickserv nil nickserv-info)
"NickServ"))
(identify-word (or (erc-nickserv-alist-ident-keyword
nil nickserv-info)
"IDENTIFY"))
(nick (if (erc-nickserv-alist-use-nick-p nil nickserv-info)
(concat nick " ")
""))
(msgtype (or (erc-nickserv-alist-ident-command nil nickserv-info)
"PRIVMSG")))
(erc-message msgtype
(concat nickserv " " identify-word " " nick password))))
(defun erc-nickserv-call-identify-function (nickname)
"Call `erc-nickserv-identify' with NICKNAME."
(declare (obsolete erc-nickserv-identify "28.1"))
(erc-nickserv-identify nil nickname))
;;;###autoload
(defun erc-nickserv-identify (&optional password nick)
"Identify to NickServ immediately.
Identification will either use NICK or the current nick if not
provided, and some password obtained through
`erc-nickserv-get-password' (which see). If no password can be
found, an error is reported trough `erc-error'.
Interactively, the user will be prompted for NICK, an empty
string meaning to default to the current nick.
Returns t if the identify message could be sent, nil otherwise."
(interactive
(list (read-passwd
(format "NickServ password for %s on %s (RET to cancel): "
(erc-current-nick)
(or (and (erc-network)
(symbol-name (erc-network)))
"Unknown network")))))
(when (and password (not (string= "" password)))
(let* ((erc-auto-discard-away nil)
(network (erc-network))
(nickserv-info (assoc network erc-nickserv-alist))
(nickserv (or (erc-nickserv-alist-nickserv nil nickserv-info)
"NickServ"))
(identify-word (or (erc-nickserv-alist-ident-keyword
nil nickserv-info)
"IDENTIFY"))
(nick (if (erc-nickserv-alist-use-nick-p nil nickserv-info)
(concat (erc-current-nick) " ")
""))
(msgtype (or (erc-nickserv-alist-ident-command nil nickserv-info)
"PRIVMSG")))
(erc-message msgtype
(concat nickserv " " identify-word " " nick password)))))
(list
nil
(read-from-minibuffer "Nickname: " nil nil nil
'erc-nick-history-list (erc-current-nick))))
(unless (and nick (not (string= nick "")))
(setq nick (erc-current-nick)))
(unless password
(setq password (erc-nickserv-get-password nick)))
(if password
(erc-nickserv-send-identify nick password)
(erc-error "Cannot find a password for nickname %s"
nick)
nil))
(provide 'erc-services)