Ignore non-existing or empty files in auth-sources

* doc/misc/auth.texi: Replace @code{"..."} by @t{"..."}.
(Help for users): Describe property lists format.  Explain, that
empty files in auth-sources are ignored when
auth-source-ignore-empty-file is non-nil.
(Help for developers): Add auth-source-creation-defaults to vindex.

* etc/NEWS: Introduce auth-source-ignore-empty-file.
Presentational fixes and improvements.

* lisp/auth-source.el (auth-source-ignore-empty-file): New defcustom.
(auth-source-backends-parser-file): Use it.  (Bug#9113)

* test/lisp/auth-source-tests.el (auth-source-validate-backend):
Let-bind `auth-source-ignore-empty-file'.
(auth-source-test-searches): Set file suffix.
(auth-source-test-netrc-create-secret): Adapt test.
This commit is contained in:
Michael Albinus 2025-09-09 23:20:56 +02:00
parent a2d4034242
commit d1221a427f
4 changed files with 136 additions and 75 deletions

View file

@ -136,9 +136,9 @@ You can use spaces inside a password or other token by surrounding the
token with either single or double quotes.
You can use apostrophes inside a password or other token by
surrounding it with double quotes, e.g., @code{"he'llo"}. Similarly you
surrounding it with double quotes, e.g., @t{"he'llo"}. Similarly you
can use double quotes inside a password or other token by surrounding
it with apostrophes, e.g., @code{'he"llo'}. You can't mix both (so a
it with apostrophes, e.g., @t{'he"llo'}. You can't mix both (so a
password or other token can't have both apostrophes and double quotes).
All this is optional. You could just say (but we don't recommend it,
@ -157,7 +157,7 @@ library encourages this confusion by accepting both, as you'll see
later.
If you have problems with the search, set @code{auth-source-debug} to
@code{'trivia} and see what host, port, and user the library is
@code{trivia} and see what host, port, and user the library is
checking in the @file{*Messages*} buffer. Ditto for any other
problems, your first step is always to see what's being checked. The
second step, of course, is to write a blog entry about it and wait for
@ -267,16 +267,34 @@ earlier. Since Tramp has about 88 connection methods, this may be
necessary if you have an unusual (see earlier comment on those) setup.
@xref{Password handling, Password handling,, tramp, Tramp}.
The netrc format is directly translated into JSON, if you are into
that sort of thing. Just point to a JSON file with entries like this:
The netrc format is directly translated into JSON, if you are into that
sort of thing. Just point to a file which has the name extension
@file{.json} with entries like this:
@example
[
@{ "machine": "yourmachine.com", "port": "http",
"login": "testuser", "password": "testpass" @}
"login": "testuser", "password": "testpass" @}
]
@end example
It is also possible to translate this into property lists, used in files
with name extension @file{.plist}. Its format is described in the
@file{plstore.el} library:
@example
(("foo" :host "yourmachine.com" :port "http"
:user "testuser" :password "testpass"))
@end example
@vindex auth-source-ignore-empty-file
File-based data stores are ignored in @code{auth-sources}, if the
underlying data file does not exist, or is empty. This is relevant, if
a new secret is stored in such a file; the first usable entry of
@code{auth-sources} is selected as target. If you want also empty or
not existing files to be selected, set the user option
@code{auth-source-ignore-empty-file} to @code{nil}.
@node Multiple GMail accounts with Gnus
@chapter Multiple GMail accounts with Gnus
@ -335,12 +353,12 @@ sometimes called a @samp{keyring} or @samp{wallet} in GNOME Keyring
and KDE Wallet but it's the same thing, a group of secrets.
Collections are personal and protected so only the owner can open them.
The most common collection is called @code{"login"}.
The most common collection is called @t{"login"}.
A collection can have an alias. The alias @code{"default"} is
A collection can have an alias. The alias @t{"default"} is
commonly used so the clients don't have to know the specific name of
the collection they open. Other aliases are not supported yet.
Since aliases are globally accessible, set the @code{"default"} alias
Since aliases are globally accessible, set the @t{"default"} alias
only when you're sure it's appropriate.
@defun secrets-list-collections
@ -349,31 +367,31 @@ This function returns all the collection names as a list.
@defun secrets-set-alias collection alias
Set @var{alias} as alias of collection labeled @var{collection}.
Currently only the alias @code{"default"} is supported.
Currently only the alias @t{"default"} is supported.
@end defun
@defun secrets-get-alias alias
Return the collection name @var{alias} is referencing to.
Currently only the alias @code{"default"} is supported.
Currently only the alias @t{"default"} is supported.
@end defun
Collections can be created and deleted by the functions
@code{secrets-create-collection} and @code{secrets-delete-collection}.
Usually, this is not done from within Emacs. Do not delete standard
collections such as @code{"login"}.
collections such as @t{"login"}.
With GNOME Keyring, there exists a special collection called
@code{"session"}, which has the lifetime of the user being logged in.
@t{"session"}, which has the lifetime of the user being logged in.
Its data is not stored on disk and goes away when the user logs out.
Therefore, it can be used to store and retrieve secret items
temporarily. The @code{"session"} collection is better than a
temporarily. The @t{"session"} collection is better than a
persistent collection when the secret items should not live
permanently. The @code{"session"} collection can be addressed either
by the string @code{"session"}, or by @code{nil}, whenever a
permanently. The @t{"session"} collection can be addressed either
by the string @t{"session"}, or by @code{nil}, whenever a
collection parameter is needed.
However, other Secret Service provider don't create this temporary
@code{"session"} collection. You must check first that this
@t{"session"} collection. You must check first that this
collection exists, before you use it.
@defun secrets-list-items collection
@ -451,12 +469,12 @@ in @code{secrets-create-item}. Example:
The auth-source library uses the @file{secrets.el} library and thus
the Secret Service API when you specify a source matching
@code{"secrets:COLLECTION"}. For instance, you could use
@code{"secrets:session"} to use the @code{"session"} collection, open only
for the lifetime of Emacs. Or you could use @code{"secrets:Login"} to
open the @code{"Login"} collection. As a special case, you can use the
@t{"secrets:@var{collection}"}. For instance, you could use
@t{"secrets:session"} to use the @t{"session"} collection, open only
for the lifetime of Emacs. Or you could use @t{"secrets:Login"} to
open the @t{"Login"} collection. As a special case, you can use the
symbol @code{default} in @code{auth-sources} (not a string, but a
symbol) to specify the @code{"default"} alias. Here is a contrived
symbol) to specify the @t{"default"} alias. Here is a contrived
example that sets @code{auth-sources} to search three collections and
then fall back to @file{~/.authinfo.gpg}.
@ -578,7 +596,7 @@ expecting to query multiple backends uniformly, try flipping it to
The auth-source library lets you control logging output easily.
@defopt auth-source-debug
Set this user option to @code{'trivia} to see lots of output in
Set this user option to @code{trivia} to see lots of output in
@file{*Messages*}, or set it to a function that behaves like
@code{message} to do your own logging.
@end defopt
@ -611,6 +629,7 @@ from Gnus's @code{nnimap.el}.
nil)))
@end example
@vindex auth-source-creation-defaults
This call requires the user and password (secret) to be in the
results. It also requests that an entry be created if it doesn't
exist already. While the created entry is being assembled, the shown
@ -636,7 +655,7 @@ authentication information we just used, if it was newly created.''
After the first time it's called, the @code{:save-function} will not
run again (but it will log something if you have set
@code{auth-source-debug} to @code{'trivia}). This is so it won't ask
@code{auth-source-debug} to @code{trivia}). This is so it won't ask
the same question again, which is annoying.
So the responsibility of the API user that specified @code{:create t}

View file

@ -189,10 +189,10 @@ be updated as you type, or nil to suppress this always. Note that for
large or inefficient completion tables this can slow down typing.
---
*** RET chooses the completion selected with M-<up>/M-<down>
If a completion candidate is selected with M-<up> or M-<down>, hitting
RET will exit completion with that as the result. This works both in
minibuffer completion and in-buffer completion. This supersedes
*** 'RET' chooses the completion selected with 'M-<up>/M-<down>'.
If a completion candidate is selected with 'M-<up>' or 'M-<down>',
hitting 'RET' will exit completion with that as the result. This works
both in minibuffer completion and in-buffer completion. This supersedes
'minibuffer-completion-auto-choose', which previously provided similar
behavior; that variable is now nil by default.
@ -525,10 +525,10 @@ project.
The value must be an alist where each element must be in the form:
(WHEN . PREDICATE)
(WHEN . PREDICATE)
where WHEN specifies where the deletion will be performed, and PREDICATE
a function which takes one argument, and must return non-nil if the
is a function which takes one argument, and must return non-nil if the
project should be removed.
---
@ -763,6 +763,17 @@ you could already use 'C-u C-x C-n' to clear the goal column.
* Changes in Specialized Modes and Packages in Emacs 31.1
** Auth Source
+++
*** Non-existing or empty files are ignored in 'auth-sources'.
File-based data stores are ignored in auth-sources, if the
underlying data file does not exist, or is empty. This is relevant, if
a new secret is stored in such a file; the first usable entry of
auth-sources is selected as target. If you want also empty or not
existing files to be selected, set the user option
auth-source-ignore-empty-file to nil.
** Autoinsert
+++
@ -782,10 +793,12 @@ the default UI you get, i.e., when 'register-use-preview' is 'traditional'.
+++
*** New user option 'treesit-enabled-modes'.
You can customize it either to t to enable all available ts-modes,
or to select a list of ts-modes to enable. Depending on customization,
it modifies the variable 'major-mode-remap-alist' from the corresponding
variable 'treesit-major-mode-remap-alist' prepared by ts-mode packages.
You can customize it either to t to enable all available tree-sitter
based modes, or to select a list of tree-sitter based modes to enable.
Depending on customization, it modifies the variable
'major-mode-remap-alist' from the corresponding variable
'treesit-major-mode-remap-alist' prepared by tree-sitter based mode
packages.
*** New user option 'treesit-auto-install-grammar'.
It controls the automatic installation of tree-sitter grammar libraries
@ -1003,9 +1016,9 @@ option controls how much is indented for method chaining.
---
*** 'php-ts-mode' now depends on 'mhtml-ts-mode'.
The direct dependency on js-ts-mode, css-ts-mode and html-ts-mode has
now been replaced by mhtml-ts-mode. Navigation, Outline and Imenu
work for all languages and code maintenance is easier.
The direct dependency on 'js-ts-mode', 'css-ts-mode' and 'html-ts-mode'
has now been replaced by mhtml-ts-mode. Navigation, Outline and Imenu
work for all languages, and code maintenance is easier.
---
*** 'php-ts-mode-run-php-webserver' can now accept a custom "php.ini" file.
@ -1016,7 +1029,7 @@ argument, 'php-ts-mode-run-php-webserver' prompts for the config file as
well as for other connection parameters.
---
*** The option 'php-ts-mode-css-fontify-colors' has been removed.
*** The user option 'php-ts-mode-css-fontify-colors' has been removed.
'mhtml-ts-mode-css-fontify-colors' replaces this option.
---
@ -1040,8 +1053,8 @@ When non nil, it highlights unknown PHPDOC tags using
---
*** New command 'php-ts-mode-show-ini'.
Show the location of the PHP ini files, if the buffer is associated to a remote
PHP file show the remote PHP ini files.
Show the location of the PHP ini files. If the current buffer is
associated to a remote PHP file, show the remote PHP ini files.
** Rust-ts mode
@ -1262,10 +1275,10 @@ If 'whitespace-style' includes 'missing-newline-at-eof' (which is the
default), the 'whitespace-cleanup' function will now add the newline.
---
*** 'whitespace-mode' now can prettify page delimiter characters (^L).
*** 'whitespace-mode' now can prettify page delimiter characters ('^L').
If 'page-delimiters' is set in 'whitespace-style', or the new minor mode
'whitespace-page-delimiters-mode' is on, the page delimiter characters
(^L) are displayed as a pretty horizontal line that spans the entire
('^L') are displayed as a pretty horizontal line that spans the entire
width of the window. The new 'whitespace-page-delimiter' face can be
used to customize the appearence.
@ -2154,7 +2167,7 @@ statuses to files, and 'C-x v v' behaved subtly differently for the two
statuses. The combination of these differences between backends and in
'C-x v v' behavior was confusing. Now,
- in VC-Dir, you can use 'C-x v v' on missing files to mark them as
- in VC Directory, you can use 'C-x v v' on missing files to mark them as
removed
- when committing, you can include missing files in a set of files with
different statuses, just like you've always been able to include
@ -2259,7 +2272,7 @@ backend functions instead. These are jointly sufficient to support the
*** Marking revisions in Log View now works more like other modes.
Previously, 'm' toggled whether the current revision was marked, and
didn't advance point. Now 'm' only adds marks, 'u' removes marks, and
both advance point, like how marking works in Dired and VC-Dir.
both advance point, like how marking works in Dired and VC Directory.
You can get back the old behavior with something like this:
(with-eval-after-load 'log-view
@ -2332,7 +2345,7 @@ packages.
** Rcirc
+++
*** Authentication via NickServ can access password from 'auth-source'.
*** Authentication via NickServ can access passwords with auth-source.el.
For details, consult 'rcirc-authinfo'.
** Xref
@ -2559,10 +2572,10 @@ If non-nil, FFAP always finds remote files in buffers with remote
'default-directory'. If nil, FFAP finds local files first for absolute
file names in above buffers. The default is nil.
** Debugging
** Edebug
+++
*** New command 'edebug-bounce-to-previous-value' (bound to 'P')
*** New command 'edebug-bounce-to-previous-value' (bound to 'P').
This command temporarily displays the outside current buffer with the
outside point corresponding to the previous value, where the previous
value is what Edebug has evaluated before its last stop point or what
@ -2603,7 +2616,7 @@ widths based on content, optimizing display space and readability.
*** New user option 'elisp-flymake-byte-compile-executable'.
This allows customizing the Emacs executable used for Flymake byte
compilation in emacs-lisp-mode. This option should be set when editing
compilation in 'emacs-lisp-mode'. This option should be set when editing
Lisp code which will run with a different Emacs version than the running
Emacs, such as code from an older or newer version of Emacs. This will
provide more accurate warnings from byte compilation.
@ -2854,15 +2867,15 @@ on GNU/Linux systems.
---
** New variable 'tty-cursor-movement-use-TAB-BS'.
The display optimization where the combination TAB characters +
BACKSPACE is used to move to a position on a TTY frame is now disabled
The display optimization where the combination 'TAB' characters +
'BACKSPACE' is used to move to a position on a TTY frame is now disabled
by default and controlled by this variable; it can be set to non-nil
to keep the old behavior. This change is to accomodate screen
readers.
+++
** A thread's current buffer can now be killed.
We introduce a new attribute for threads called buffer-disposition.
We introduce a new attribute for threads called 'buffer-disposition'.
See the new argument in 'make-thread'. The default value allows the
thread's current buffer to be killed by another thread. This does not
apply to the main thread's buffer.

View file

@ -370,6 +370,16 @@ soon as a function returns non-nil.")
:type 'ignore)))
(auth-source-backend-parse-parameters entry backend)))
(defcustom auth-source-ignore-empty-file t
"If set non-nil, file-based backends with no data are ignored.
A backend is ignored, when the underlying file does not exist, or it is
empty. Consequently, no newly created entry is saved in an empty
backend when this user option is non-nil.
Supported backend types are `netrc', `plstore' and `json'."
:version "31.1"
:type 'boolean)
(defun auth-source-backends-parser-file (entry)
;; take just a file name use it as a netrc/plist file
;; matching any user, host, and protocol
@ -384,26 +394,41 @@ soon as a function returns non-nil.")
(extension (or (and (stringp source-without-gpg)
(file-name-extension source-without-gpg))
"")))
(when (stringp source)
(cond
((equal extension "plist")
(auth-source-backend
:source source
:type 'plstore
:search-function #'auth-source-plstore-search
:create-function #'auth-source-plstore-create
:data (plstore-open source)))
((member-ignore-case extension '("json"))
(auth-source-backend
:source source
:type 'json
:search-function #'auth-source-json-search))
(t
(auth-source-backend
:source source
:type 'netrc
:search-function #'auth-source-netrc-search
:create-function #'auth-source-netrc-create))))))
(if (and (stringp source)
(or (not auth-source-ignore-empty-file)
(and-let*
(;; File exists.
(attr (file-attributes source))
;; File isn't empty.
((not (zerop (file-attribute-size attr))))))))
(cond
((equal extension "plist")
(auth-source-backend
:source source
:type 'plstore
:search-function #'auth-source-plstore-search
:create-function #'auth-source-plstore-create
:data (plstore-open source)))
((member-ignore-case extension '("json"))
(auth-source-backend
:source source
:type 'json
:search-function #'auth-source-json-search))
(t
(auth-source-backend
:source source
:type 'netrc
:search-function #'auth-source-netrc-search
:create-function #'auth-source-netrc-create)))
(when auth-source-debug
(auth-source-do-warn
(concat "auth-source-backend-parse: "
"not existing or empty file, ignoring spec: %S")
entry))
(auth-source-backend
:source ""
:type 'ignore))))
;; Note this function should be last in the parser functions, so we add it first
(add-hook 'auth-source-backend-parser-functions #'auth-source-backends-parser-file)

View file

@ -37,7 +37,8 @@
(type . ignore))))
(defun auth-source-validate-backend (source validation-alist)
(let ((backend (auth-source-backend-parse source)))
(let* (auth-source-ignore-empty-file
(backend (auth-source-backend-parse source)))
(should (auth-source-backend-p backend))
(dolist (pair validation-alist)
(should (equal (eieio-oref backend (car pair)) (cdr pair))))))
@ -308,7 +309,7 @@
:host "b1" :port "b2" :user "b3")
)))
(ert-with-temp-file netrc-file
:text (mapconcat 'identity entries "\n")
:suffix "auth-source-test" :text (mapconcat 'identity entries "\n")
(let ((auth-sources (list netrc-file))
(auth-source-do-cache nil)
found found-as-string)
@ -374,10 +375,13 @@
"%s@%s" (plist-get auth-info :user) (plist-get auth-info :host)))))))
(ert-deftest auth-source-test-netrc-create-secret ()
(ert-with-temp-file empty-file :suffix "auth-source-test"
(ert-with-temp-file netrc-file
:suffix "auth-source-test"
(let* ((auth-sources (list netrc-file))
:text "machine a1 port a2 user a3 password a4"
(let* ((auth-sources (list empty-file netrc-file))
(auth-source-save-behavior t)
(auth-source-ignore-empty-file t)
host auth-info auth-passwd)
(dolist (passwd '("foo" "" nil))
;; Redefine `read-*' in order to avoid interactive input.
@ -415,7 +419,7 @@
(string-equal (plist-get auth-info :user) (user-login-name)))
(should (string-equal (plist-get auth-info :host) host))
(should (string-equal auth-passwd passwd))
(should (search-forward host nil 'noerror)))))))))
(should (search-forward host nil 'noerror))))))))))
(ert-deftest auth-source-delete ()
(ert-with-temp-file netrc-file