Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NickServ identification: Prompt for password last, overall simplifications #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions etc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -1528,14 +1528,20 @@ https://www.w3.org/TR/xml/#charsets). Now it rejects such strings.

** 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 true, the user used to be
unconditionally prompted interactively for a password, regardless of
the content of `erc-nickserv-passwords', which was effectively ignored
(same for the new 'erc-use-auth-source-for-nickserv-password'). This
limitation is now removed, 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.
Expand Down
161 changes: 91 additions & 70 deletions lisp/erc/erc-services.el
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,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"
:group 'erc-services
:type 'boolean)
Expand Down Expand Up @@ -400,85 +399,107 @@ 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 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 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)))

(defun erc-nickserv-get-password (nickname)
"Return the password for NICKNAME from configured sources.

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))))
(unless (and (eq erc-nickserv-identify-mode 'both)
(erc-nickserv-alist-regexp (erc-network)))
(erc-nickserv-identify nick)))

(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.

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))))

;;;###autoload
(defun erc-nickserv-identify (&optional 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
(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)))
(let ((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)

Expand Down