* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true @ 2024-08-03 11:12 Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-08-09 18:02 ` J.P. 0 siblings, 1 reply; 6+ messages in thread From: Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-08-03 11:12 UTC (permalink / raw) To: 72441 I noticed that auth-source-pass doesn't match agains password file attributes such as those containing :user and only matches password files which contain a host and a user when auth-source-pass-extra-query-keywords is true. Steps to reproduce: 1. Setup pass with the following structure WorkingTest/example.com/foo FailingTest/example2.com FailingTest/example3.com with user: foo in the password file 2. (auth-source-pass-enable) 3. (setq auth-source-pass-extra-query-keywords t) 4. (auth-source-search :host "example" :user "foo") -> works 5. (auth-source-search :host "example2.com") -> fails 6. (auth-source-search :host "example3.com" :user "foo") Auth-source-pass should be able to query the password file for additional attributes if one of the previous attributes such as :host match to it. Quering the file attributes is quite important in use cases where it doesn't make sense to the user to have a host-folder/user-file structure in cases where there's only one password for said host. Same it should maybe also match against :host if no user was provided, I don't know how other sources do this thou. In GNU Emacs 31.0.50 (build 1, x86_64-suse-linux-gnu, GTK+ Version 3.24.43, cairo version 1.18.0) Windowing system distributor 'The X.Org Foundation', version 11.0.12101012 System Description: openSUSE Tumbleweed Configured using: 'configure --disable-build-details --without-pop --with-mailutils --without-hesiod --with-gameuser=:games --with-kerberos --with-kerberos5 --with-file-notification=inotify --with-modules --enable-autodepend --enable-link-time-optimization --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share --localstatedir=/var --sharedstatedir=/var/lib --libexecdir=/usr/libexec --with-file-notification=yes --libdir=/usr/lib64 --with-native-compilation=aot --enable-locallisppath=/usr/share/emacs/31.0.50/site-lisp:/usr/share/emacs/site-lisp --with-x --with-xim --with-sound --with-xpm --with-jpeg --with-tiff --with-gif --with-png --with-rsvg --with-dbus --with-xft --without-gpm --with-tree-sitter --with-x-toolkit=gtk --without-pgtk --with-toolkit-scroll-bars --x-includes=/usr/include --x-libraries=/usr/lib64 --with-libotf --with-m17n-flt --with-cairo --with-xwidgets --build=x86_64-suse-linux --with-dumping=pdumper build_alias=x86_64-suse-linux 'CC=sccache cc' 'CFLAGS=-O2 -Wall -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -Werror=return-type -flto=auto -march=znver3 -mmmx -mpopcnt -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -mavx2 -msse4a -mno-fma4 -mno-xop -mfma -mno-avx512f -mbmi -mbmi2 -maes -mpclmul -mno-avx512vl -mno-avx512bw -mno-avx512dq -mno-avx512cd -mno-avx512er -mno-avx512pf -mno-avx512vbmi -mno-avx512ifma -mno-avx5124vnniw -mno-avx5124fmaps -mno-avx512vpopcntdq -mno-avx512vbmi2 -mno-gfni -mvpclmulqdq -mno-avx512vnni -mno-avx512bitalg -mno-avx512bf16 -mno-avx512vp2intersect -mno-3dnow -madx -mabm -mno-cldemote -mclflushopt -mclwb -mclzero -mcx16 -mno-enqcmd -mf16c -mfsgsbase -mfxsr -mno-hle -msahf -mno-lwp -mlzcnt -mmovbe -mno-movdir64b -mno-movdiri -mmwaitx -mno-pconfig -mpku -mno-prefetchwt1 -mprfchw -mno-ptwrite -mrdpid -mrdrnd -mrdseed -mno-rtm -mno-serialize -mno-sgx -msha -mshstk -mno-tbm -mno-tsxldtrk -mvaes -mno-waitpkg -mwbnoinvd -mxsave -mxsavec -mxsaveopt -mxsaves -mno-amx-tile -mno-amx-int8 -mno-amx-bf16 -mno-uintr -mno-hreset -mno-kl -mno-widekl -mno-avxvnni -mno-avx512fp16 -mno-avxifma -mno-avxvnniint8 -mno-avxneconvert -mno-cmpccxadd -mno-amx-fp16 -mno-prefetchi -mno-raoint -mno-amx-complex --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=512 -mtune=znver3 -fno-optimize-sibling-calls -g -D_GNU_SOURCE -DGDK_DISABLE_DEPRECATION_WARNINGS -DGLIB_DISABLE_DEPRECATION_WARNINGS -pipe -Wno-pointer-sign -Wno-unused-variable -Wno-unused-label -DPDMP_BASE='\''"emacs-gtk"'\''' LDFLAGS=-Wl,-O2 'CXX=sccache c++' PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig' Configured features: ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM XINPUT2 XPM XWIDGETS GTK3 ZLIB Important settings: value of $LC_MONETARY: fi_FI.UTF-8 value of $LC_NUMERIC: POSIX value of $LANG: en_GB.UTF-8 value of $XMODIFIERS: @im=local locale-coding-system: utf-8-unix Major mode: Eshell Minor modes in effect: eshell-prompt-mode: t eshell-pred-mode: t eshell-hist-mode: t eshell-cmpl-mode: t eshell-proc-mode: t eshell-arg-mode: t circe-lagmon-mode: t magit-wip-initial-backup-mode: t magit-wip-before-change-mode: t magit-wip-after-apply-mode: t magit-wip-after-save-mode: t magit-wip-mode: t magit-auto-revert-mode: t pdf-occur-global-minor-mode: t pdf-virtual-global-minor-mode: t global-atomic-chrome-edit-mode: t minions-mode: t back-button-mode: t recentf-mode: t global-auto-revert-mode: t savehist-mode: t emms-playing-time-display-mode: t emms-playing-time-mode: t gnus-desktop-notify-mode: t tracking-mode: t org-super-agenda-mode: t goto-address-mode: t global-git-commit-mode: t projectile-mode: t global-company-mode: t company-mode: t electric-pair-mode: t editorconfig-mode: t frames-only-mode: t windmove-mode: t marginalia-mode: t which-key-mode: t dirvish-override-dired-mode: t dired-async-mode: t helm-mode: t helm-minibuffer-history-mode: t global-so-long-mode: t global-emojify-mode: t emojify-mode: t change-cursor-mode: t doom-modeline-mode: t server-mode: t helm-autoresize-mode: t desktop-save-mode: t Info-persist-history-mode: t save-place-mode: t delete-selection-mode: t override-global-mode: t tooltip-mode: t global-eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t undelete-frame-mode: t minibuffer-regexp-mode: t line-number-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: /home/bidar/.local/etc/emacs/lib/org/lisp/ox-koma-letter hides /home/bidar/.local/etc/emacs/lib/lisp/ox-koma-letter /home/bidar/.local/etc/emacs/lib/org-contrib/lisp/ox-groff hides /home/bidar/.local/etc/emacs/lib/lisp/ox-groff /home/bidar/.local/etc/emacs/lib/vim-modeline/vim-modeline hides /home/bidar/.local/etc/emacs/lib/lisp/vim-modeline /home/bidar/.local/etc/emacs/lib/lisp/htmlize hides /home/bidar/.local/etc/emacs/lib/htmlize/htmlize /home/bidar/.local/etc/emacs/lib/lisp/cursor-chg hides /home/bidar/.local/etc/emacs/lib/cursor-chg/cursor-chg /home/bidar/.local/etc/emacs/lib/cmake-mode/cmake-mode hides /usr/share/emacs/site-lisp/cmake-mode /home/bidar/.local/etc/emacs/lib/async/dired-async hides /usr/share/emacs/site-lisp/dired-async /home/bidar/.local/etc/emacs/lib/async/async-bytecomp hides /usr/share/emacs/site-lisp/async-bytecomp /home/bidar/.local/etc/emacs/lib/async/async-autoloads hides /usr/share/emacs/site-lisp/async-autoloads /home/bidar/.local/etc/emacs/lib/async/smtpmail-async hides /usr/share/emacs/site-lisp/smtpmail-async /home/bidar/.local/etc/emacs/lib/async/async hides /usr/share/emacs/site-lisp/async /home/bidar/.local/etc/emacs/lib/compat/compat hides /usr/share/emacs/site-lisp/compat /home/bidar/.local/etc/emacs/lib/compat/compat-29 hides /usr/share/emacs/site-lisp/compat-29 /home/bidar/.local/etc/emacs/lib/compat/compat-28 hides /usr/share/emacs/site-lisp/compat-28 /home/bidar/.local/etc/emacs/lib/compat/compat-27 hides /usr/share/emacs/site-lisp/compat-27 /home/bidar/.local/etc/emacs/lib/compat/compat-26 hides /usr/share/emacs/site-lisp/compat-26 /home/bidar/.local/etc/emacs/lib/compat/compat-25 hides /usr/share/emacs/site-lisp/compat-25 /home/bidar/.local/etc/emacs/lib/which-key/which-key hides /usr/share/emacs/31.0.50/lisp/which-key /home/bidar/.local/etc/emacs/lib/transient/lisp/transient hides /usr/share/emacs/31.0.50/lisp/transient /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig hides /usr/share/emacs/31.0.50/lisp/editorconfig /home/bidar/.local/etc/emacs/lib/use-package/bind-key hides /usr/share/emacs/31.0.50/lisp/bind-key /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig-tools hides /usr/share/emacs/31.0.50/lisp/editorconfig-tools /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig-fnmatch hides /usr/share/emacs/31.0.50/lisp/editorconfig-fnmatch /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig-core hides /usr/share/emacs/31.0.50/lisp/editorconfig-core /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig-core-handle hides /usr/share/emacs/31.0.50/lisp/editorconfig-core-handle /home/bidar/.local/etc/emacs/lib/editorconfig/editorconfig-conf-mode hides /usr/share/emacs/31.0.50/lisp/editorconfig-conf-mode /home/bidar/.local/etc/emacs/lib/modus-themes/theme-loaddefs hides /usr/share/emacs/31.0.50/lisp/theme-loaddefs /home/bidar/.local/etc/emacs/lib/use-package/use-package hides /usr/share/emacs/31.0.50/lisp/use-package/use-package /home/bidar/.local/etc/emacs/lib/use-package/use-package-lint hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-lint /home/bidar/.local/etc/emacs/lib/use-package/use-package-jump hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-jump /home/bidar/.local/etc/emacs/lib/use-package/use-package-ensure hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-ensure /home/bidar/.local/etc/emacs/lib/use-package/use-package-ensure-system-package hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-ensure-system-package /home/bidar/.local/etc/emacs/lib/use-package/use-package-diminish hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-diminish /home/bidar/.local/etc/emacs/lib/use-package/use-package-delight hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-delight /home/bidar/.local/etc/emacs/lib/use-package/use-package-core hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-core /home/bidar/.local/etc/emacs/lib/use-package/use-package-bind-key hides /usr/share/emacs/31.0.50/lisp/use-package/use-package-bind-key /home/bidar/.local/etc/emacs/lib/org/lisp/org-list hides /usr/share/emacs/31.0.50/lisp/org/org-list /home/bidar/.local/etc/emacs/lib/org/lisp/org-refile hides /usr/share/emacs/31.0.50/lisp/org/org-refile /home/bidar/.local/etc/emacs/lib/org/lisp/org-loaddefs hides /usr/share/emacs/31.0.50/lisp/org/org-loaddefs /home/bidar/.local/etc/emacs/lib/org/lisp/ob-lilypond hides /usr/share/emacs/31.0.50/lisp/org/ob-lilypond /home/bidar/.local/etc/emacs/lib/org/lisp/ob-core hides /usr/share/emacs/31.0.50/lisp/org/ob-core /home/bidar/.local/etc/emacs/lib/org/lisp/ox-beamer hides /usr/share/emacs/31.0.50/lisp/org/ox-beamer /home/bidar/.local/etc/emacs/lib/org/lisp/org hides /usr/share/emacs/31.0.50/lisp/org/org /home/bidar/.local/etc/emacs/lib/org/lisp/org-table hides /usr/share/emacs/31.0.50/lisp/org/org-table /home/bidar/.local/etc/emacs/lib/org/lisp/org-src hides /usr/share/emacs/31.0.50/lisp/org/org-src /home/bidar/.local/etc/emacs/lib/org/lisp/org-num hides /usr/share/emacs/31.0.50/lisp/org/org-num /home/bidar/.local/etc/emacs/lib/org/lisp/org-indent hides /usr/share/emacs/31.0.50/lisp/org/org-indent /home/bidar/.local/etc/emacs/lib/org/lisp/org-capture hides /usr/share/emacs/31.0.50/lisp/org/org-capture /home/bidar/.local/etc/emacs/lib/org/lisp/org-persist hides /usr/share/emacs/31.0.50/lisp/org/org-persist /home/bidar/.local/etc/emacs/lib/org/lisp/org-element hides /usr/share/emacs/31.0.50/lisp/org/org-element /home/bidar/.local/etc/emacs/lib/org/lisp/org-element-ast hides /usr/share/emacs/31.0.50/lisp/org/org-element-ast /home/bidar/.local/etc/emacs/lib/org/lisp/org-colview hides /usr/share/emacs/31.0.50/lisp/org/org-colview /home/bidar/.local/etc/emacs/lib/org/lisp/ob-shell hides /usr/share/emacs/31.0.50/lisp/org/ob-shell /home/bidar/.local/etc/emacs/lib/org/lisp/ob-python hides /usr/share/emacs/31.0.50/lisp/org/ob-python /home/bidar/.local/etc/emacs/lib/org/lisp/ob-R hides /usr/share/emacs/31.0.50/lisp/org/ob-R /home/bidar/.local/etc/emacs/lib/org/lisp/org-version hides /usr/share/emacs/31.0.50/lisp/org/org-version /home/bidar/.local/etc/emacs/lib/org/lisp/ox hides /usr/share/emacs/31.0.50/lisp/org/ox /home/bidar/.local/etc/emacs/lib/org/lisp/ox-texinfo hides /usr/share/emacs/31.0.50/lisp/org/ox-texinfo /home/bidar/.local/etc/emacs/lib/org/lisp/ox-publish hides /usr/share/emacs/31.0.50/lisp/org/ox-publish /home/bidar/.local/etc/emacs/lib/org/lisp/ox-org hides /usr/share/emacs/31.0.50/lisp/org/ox-org /home/bidar/.local/etc/emacs/lib/org/lisp/ox-odt hides /usr/share/emacs/31.0.50/lisp/org/ox-odt /home/bidar/.local/etc/emacs/lib/org/lisp/ox-md hides /usr/share/emacs/31.0.50/lisp/org/ox-md /home/bidar/.local/etc/emacs/lib/org/lisp/ox-man hides /usr/share/emacs/31.0.50/lisp/org/ox-man /home/bidar/.local/etc/emacs/lib/org/lisp/ox-latex hides /usr/share/emacs/31.0.50/lisp/org/ox-latex /home/bidar/.local/etc/emacs/lib/org/lisp/ox-koma-letter hides /usr/share/emacs/31.0.50/lisp/org/ox-koma-letter /home/bidar/.local/etc/emacs/lib/org/lisp/ox-icalendar hides /usr/share/emacs/31.0.50/lisp/org/ox-icalendar /home/bidar/.local/etc/emacs/lib/org/lisp/ox-html hides /usr/share/emacs/31.0.50/lisp/org/ox-html /home/bidar/.local/etc/emacs/lib/org/lisp/ox-ascii hides /usr/share/emacs/31.0.50/lisp/org/ox-ascii /home/bidar/.local/etc/emacs/lib/org/lisp/org-timer hides /usr/share/emacs/31.0.50/lisp/org/org-timer /home/bidar/.local/etc/emacs/lib/org/lisp/org-tempo hides /usr/share/emacs/31.0.50/lisp/org/org-tempo /home/bidar/.local/etc/emacs/lib/org/lisp/org-protocol hides /usr/share/emacs/31.0.50/lisp/org/org-protocol /home/bidar/.local/etc/emacs/lib/org/lisp/org-plot hides /usr/share/emacs/31.0.50/lisp/org/org-plot /home/bidar/.local/etc/emacs/lib/org/lisp/org-pcomplete hides /usr/share/emacs/31.0.50/lisp/org/org-pcomplete /home/bidar/.local/etc/emacs/lib/org/lisp/org-mouse hides /usr/share/emacs/31.0.50/lisp/org/org-mouse /home/bidar/.local/etc/emacs/lib/org/lisp/org-mobile hides /usr/share/emacs/31.0.50/lisp/org/org-mobile /home/bidar/.local/etc/emacs/lib/org/lisp/org-macs hides /usr/share/emacs/31.0.50/lisp/org/org-macs /home/bidar/.local/etc/emacs/lib/org/lisp/org-macro hides /usr/share/emacs/31.0.50/lisp/org/org-macro /home/bidar/.local/etc/emacs/lib/org/lisp/org-lint hides /usr/share/emacs/31.0.50/lisp/org/org-lint /home/bidar/.local/etc/emacs/lib/org/lisp/org-keys hides /usr/share/emacs/31.0.50/lisp/org/org-keys /home/bidar/.local/etc/emacs/lib/org/lisp/org-inlinetask hides /usr/share/emacs/31.0.50/lisp/org/org-inlinetask /home/bidar/.local/etc/emacs/lib/org/lisp/org-id hides /usr/share/emacs/31.0.50/lisp/org/org-id /home/bidar/.local/etc/emacs/lib/org/lisp/org-habit hides /usr/share/emacs/31.0.50/lisp/org/org-habit /home/bidar/.local/etc/emacs/lib/org/lisp/org-goto hides /usr/share/emacs/31.0.50/lisp/org/org-goto /home/bidar/.local/etc/emacs/lib/org/lisp/org-footnote hides /usr/share/emacs/31.0.50/lisp/org/org-footnote /home/bidar/.local/etc/emacs/lib/org/lisp/org-fold hides /usr/share/emacs/31.0.50/lisp/org/org-fold /home/bidar/.local/etc/emacs/lib/org/lisp/org-fold-core hides /usr/share/emacs/31.0.50/lisp/org/org-fold-core /home/bidar/.local/etc/emacs/lib/org/lisp/org-feed hides /usr/share/emacs/31.0.50/lisp/org/org-feed /home/bidar/.local/etc/emacs/lib/org/lisp/org-faces hides /usr/share/emacs/31.0.50/lisp/org/org-faces /home/bidar/.local/etc/emacs/lib/org/lisp/org-entities hides /usr/share/emacs/31.0.50/lisp/org/org-entities /home/bidar/.local/etc/emacs/lib/org/lisp/org-duration hides /usr/share/emacs/31.0.50/lisp/org/org-duration /home/bidar/.local/etc/emacs/lib/org/lisp/org-datetree hides /usr/share/emacs/31.0.50/lisp/org/org-datetree /home/bidar/.local/etc/emacs/lib/org/lisp/org-cycle hides /usr/share/emacs/31.0.50/lisp/org/org-cycle /home/bidar/.local/etc/emacs/lib/org/lisp/org-ctags hides /usr/share/emacs/31.0.50/lisp/org/org-ctags /home/bidar/.local/etc/emacs/lib/org/lisp/org-crypt hides /usr/share/emacs/31.0.50/lisp/org/org-crypt /home/bidar/.local/etc/emacs/lib/org/lisp/org-compat hides /usr/share/emacs/31.0.50/lisp/org/org-compat /home/bidar/.local/etc/emacs/lib/org/lisp/org-clock hides /usr/share/emacs/31.0.50/lisp/org/org-clock /home/bidar/.local/etc/emacs/lib/org/lisp/org-attach hides /usr/share/emacs/31.0.50/lisp/org/org-attach /home/bidar/.local/etc/emacs/lib/org/lisp/org-attach-git hides /usr/share/emacs/31.0.50/lisp/org/org-attach-git /home/bidar/.local/etc/emacs/lib/org/lisp/org-archive hides /usr/share/emacs/31.0.50/lisp/org/org-archive /home/bidar/.local/etc/emacs/lib/org/lisp/org-agenda hides /usr/share/emacs/31.0.50/lisp/org/org-agenda /home/bidar/.local/etc/emacs/lib/org/lisp/ol hides /usr/share/emacs/31.0.50/lisp/org/ol /home/bidar/.local/etc/emacs/lib/org/lisp/ol-w3m hides /usr/share/emacs/31.0.50/lisp/org/ol-w3m /home/bidar/.local/etc/emacs/lib/org/lisp/ol-rmail hides /usr/share/emacs/31.0.50/lisp/org/ol-rmail /home/bidar/.local/etc/emacs/lib/org/lisp/ol-mhe hides /usr/share/emacs/31.0.50/lisp/org/ol-mhe /home/bidar/.local/etc/emacs/lib/org/lisp/ol-man hides /usr/share/emacs/31.0.50/lisp/org/ol-man /home/bidar/.local/etc/emacs/lib/org/lisp/ol-irc hides /usr/share/emacs/31.0.50/lisp/org/ol-irc /home/bidar/.local/etc/emacs/lib/org/lisp/ol-info hides /usr/share/emacs/31.0.50/lisp/org/ol-info /home/bidar/.local/etc/emacs/lib/org/lisp/ol-gnus hides /usr/share/emacs/31.0.50/lisp/org/ol-gnus /home/bidar/.local/etc/emacs/lib/org/lisp/ol-eww hides /usr/share/emacs/31.0.50/lisp/org/ol-eww /home/bidar/.local/etc/emacs/lib/org/lisp/ol-eshell hides /usr/share/emacs/31.0.50/lisp/org/ol-eshell /home/bidar/.local/etc/emacs/lib/org/lisp/ol-doi hides /usr/share/emacs/31.0.50/lisp/org/ol-doi /home/bidar/.local/etc/emacs/lib/org/lisp/ol-docview hides /usr/share/emacs/31.0.50/lisp/org/ol-docview /home/bidar/.local/etc/emacs/lib/org/lisp/ol-bibtex hides /usr/share/emacs/31.0.50/lisp/org/ol-bibtex /home/bidar/.local/etc/emacs/lib/org/lisp/ol-bbdb hides /usr/share/emacs/31.0.50/lisp/org/ol-bbdb /home/bidar/.local/etc/emacs/lib/org/lisp/oc hides /usr/share/emacs/31.0.50/lisp/org/oc /home/bidar/.local/etc/emacs/lib/org/lisp/oc-natbib hides /usr/share/emacs/31.0.50/lisp/org/oc-natbib /home/bidar/.local/etc/emacs/lib/org/lisp/oc-csl hides /usr/share/emacs/31.0.50/lisp/org/oc-csl /home/bidar/.local/etc/emacs/lib/org/lisp/oc-bibtex hides /usr/share/emacs/31.0.50/lisp/org/oc-bibtex /home/bidar/.local/etc/emacs/lib/org/lisp/oc-biblatex hides /usr/share/emacs/31.0.50/lisp/org/oc-biblatex /home/bidar/.local/etc/emacs/lib/org/lisp/oc-basic hides /usr/share/emacs/31.0.50/lisp/org/oc-basic /home/bidar/.local/etc/emacs/lib/org/lisp/ob hides /usr/share/emacs/31.0.50/lisp/org/ob /home/bidar/.local/etc/emacs/lib/org/lisp/ob-tangle hides /usr/share/emacs/31.0.50/lisp/org/ob-tangle /home/bidar/.local/etc/emacs/lib/org/lisp/ob-table hides /usr/share/emacs/31.0.50/lisp/org/ob-table /home/bidar/.local/etc/emacs/lib/org/lisp/ob-sqlite hides /usr/share/emacs/31.0.50/lisp/org/ob-sqlite /home/bidar/.local/etc/emacs/lib/org/lisp/ob-sql hides /usr/share/emacs/31.0.50/lisp/org/ob-sql /home/bidar/.local/etc/emacs/lib/org/lisp/ob-sed hides /usr/share/emacs/31.0.50/lisp/org/ob-sed /home/bidar/.local/etc/emacs/lib/org/lisp/ob-screen hides /usr/share/emacs/31.0.50/lisp/org/ob-screen /home/bidar/.local/etc/emacs/lib/org/lisp/ob-scheme hides /usr/share/emacs/31.0.50/lisp/org/ob-scheme /home/bidar/.local/etc/emacs/lib/org/lisp/ob-sass hides /usr/share/emacs/31.0.50/lisp/org/ob-sass /home/bidar/.local/etc/emacs/lib/org/lisp/ob-ruby hides /usr/share/emacs/31.0.50/lisp/org/ob-ruby /home/bidar/.local/etc/emacs/lib/org/lisp/ob-ref hides /usr/share/emacs/31.0.50/lisp/org/ob-ref /home/bidar/.local/etc/emacs/lib/org/lisp/ob-processing hides /usr/share/emacs/31.0.50/lisp/org/ob-processing /home/bidar/.local/etc/emacs/lib/org/lisp/ob-plantuml hides /usr/share/emacs/31.0.50/lisp/org/ob-plantuml /home/bidar/.local/etc/emacs/lib/org/lisp/ob-perl hides /usr/share/emacs/31.0.50/lisp/org/ob-perl /home/bidar/.local/etc/emacs/lib/org/lisp/ob-org hides /usr/share/emacs/31.0.50/lisp/org/ob-org /home/bidar/.local/etc/emacs/lib/org/lisp/ob-octave hides /usr/share/emacs/31.0.50/lisp/org/ob-octave /home/bidar/.local/etc/emacs/lib/org/lisp/ob-ocaml hides /usr/share/emacs/31.0.50/lisp/org/ob-ocaml /home/bidar/.local/etc/emacs/lib/org/lisp/ob-maxima hides /usr/share/emacs/31.0.50/lisp/org/ob-maxima /home/bidar/.local/etc/emacs/lib/org/lisp/ob-matlab hides /usr/share/emacs/31.0.50/lisp/org/ob-matlab /home/bidar/.local/etc/emacs/lib/org/lisp/ob-makefile hides /usr/share/emacs/31.0.50/lisp/org/ob-makefile /home/bidar/.local/etc/emacs/lib/org/lisp/ob-lua hides /usr/share/emacs/31.0.50/lisp/org/ob-lua /home/bidar/.local/etc/emacs/lib/org/lisp/ob-lob hides /usr/share/emacs/31.0.50/lisp/org/ob-lob /home/bidar/.local/etc/emacs/lib/org/lisp/ob-lisp hides /usr/share/emacs/31.0.50/lisp/org/ob-lisp /home/bidar/.local/etc/emacs/lib/org/lisp/ob-latex hides /usr/share/emacs/31.0.50/lisp/org/ob-latex /home/bidar/.local/etc/emacs/lib/org/lisp/ob-julia hides /usr/share/emacs/31.0.50/lisp/org/ob-julia /home/bidar/.local/etc/emacs/lib/org/lisp/ob-js hides /usr/share/emacs/31.0.50/lisp/org/ob-js /home/bidar/.local/etc/emacs/lib/org/lisp/ob-java hides /usr/share/emacs/31.0.50/lisp/org/ob-java /home/bidar/.local/etc/emacs/lib/org/lisp/ob-haskell hides /usr/share/emacs/31.0.50/lisp/org/ob-haskell /home/bidar/.local/etc/emacs/lib/org/lisp/ob-groovy hides /usr/share/emacs/31.0.50/lisp/org/ob-groovy /home/bidar/.local/etc/emacs/lib/org/lisp/ob-gnuplot hides /usr/share/emacs/31.0.50/lisp/org/ob-gnuplot /home/bidar/.local/etc/emacs/lib/org/lisp/ob-fortran hides /usr/share/emacs/31.0.50/lisp/org/ob-fortran /home/bidar/.local/etc/emacs/lib/org/lisp/ob-forth hides /usr/share/emacs/31.0.50/lisp/org/ob-forth /home/bidar/.local/etc/emacs/lib/org/lisp/ob-exp hides /usr/share/emacs/31.0.50/lisp/org/ob-exp /home/bidar/.local/etc/emacs/lib/org/lisp/ob-eval hides /usr/share/emacs/31.0.50/lisp/org/ob-eval /home/bidar/.local/etc/emacs/lib/org/lisp/ob-eshell hides /usr/share/emacs/31.0.50/lisp/org/ob-eshell /home/bidar/.local/etc/emacs/lib/org/lisp/ob-emacs-lisp hides /usr/share/emacs/31.0.50/lisp/org/ob-emacs-lisp /home/bidar/.local/etc/emacs/lib/org/lisp/ob-dot hides /usr/share/emacs/31.0.50/lisp/org/ob-dot /home/bidar/.local/etc/emacs/lib/org/lisp/ob-ditaa hides /usr/share/emacs/31.0.50/lisp/org/ob-ditaa /home/bidar/.local/etc/emacs/lib/org/lisp/ob-css hides /usr/share/emacs/31.0.50/lisp/org/ob-css /home/bidar/.local/etc/emacs/lib/org/lisp/ob-comint hides /usr/share/emacs/31.0.50/lisp/org/ob-comint /home/bidar/.local/etc/emacs/lib/org/lisp/ob-clojure hides /usr/share/emacs/31.0.50/lisp/org/ob-clojure /home/bidar/.local/etc/emacs/lib/org/lisp/ob-calc hides /usr/share/emacs/31.0.50/lisp/org/ob-calc /home/bidar/.local/etc/emacs/lib/org/lisp/ob-awk hides /usr/share/emacs/31.0.50/lisp/org/ob-awk /home/bidar/.local/etc/emacs/lib/org/lisp/ob-C hides /usr/share/emacs/31.0.50/lisp/org/ob-C /home/bidar/.local/etc/emacs/lib/compat/compat hides /usr/share/emacs/31.0.50/lisp/emacs-lisp/compat Features: (shadow emacsbug em-unix em-term em-script em-prompt em-pred em-ls em-hist em-glob em-extpipe em-cmpl em-dirs em-basic em-banner em-alias esh-mode esh-var eshell esh-cmd esh-ext esh-opt esh-proc esh-io esh-arg esh-module esh-module-loaddefs esh-util make-mode move-text goto-chg whitespace gitignore-mode dired-open helm-ls-git help-macro tabify gnus-search eieio-opt speedbar ezimage dframe finder-inf gnus-delay gnus-draft gitattributes-mode vc-dir two-column helm-descbinds mailalias bbdb-pgp message-attachment-reminder bbdb-message gnus-alias autocrypt-message git-rebase magit-extras shortdoc cl-print adaptive-wrap adaptive-wrap-autoloads gitconfig-mode help-fns emacsql-sqlite-builtin sqlite org-indent crux smart-region multiple-cursors mc-separate-operations rectangular-region-mode mc-mark-pop mc-edit-lines mc-hide-unmatched-lines-mode mc-mark-more html-mode-expansions sgml-mode mc-cycle-cursors multiple-cursors-core rect expand-region yaml-mode-expansions subword-mode-expansions cperl-mode-expansions text-mode-expansions cc-mode-expansions the-org-mode-expansions python-el-fgallina-expansions er-basic-expansions expand-region-core expand-region-custom char-fold helm-org-rifle misearch multi-isearch orgit-forge orgit doctor helm-command org-clock-helpers flow-fill mastodon-notifications mastodon-media mastodon-profile mastodon-auth mastodon-client plstore mastodon mastodon-search mastodon-toot persist mastodon-http request circe-lagmon ietf-drums-date gnus-gravatar gnus-cite message-view-patch forge-repos forge-tablist forge-topics forge-commands forge-semi forge-bitbucket buck forge-gogs gogs forge-gitea gtea forge-gitlab glab forge-github ghub-graphql treepy gsexp ghub forge-notify forge-revnote forge-pullreq forge-issue forge-topic yaml eieio-custom forge-post markdown-mode forge-repo forge forge-core forge-db magit-popup magit-bookmark magit-submodule magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit magit-sequence magit-notes magit-worktree magit-tag magit-merge magit-branch magit-reset magit-files magit-refs magit-status magit magit-repos magit-apply magit-wip magit-log magit-diff smerge-mode diff magit-core magit-autorevert magit-margin magit-transient magit-process magit-mode w3m-form w3m-symbol w3m w3m-hist bookmark-w3m w3m-ems w3m-favicon w3m-image w3m-fb tab-line w3m-proc w3m-util mm-archive mail-extr textsec uni-scripts idna-mapping ucs-normalize uni-confusable textsec-check gnus-async gnus-bcklg bbdb-gnus-aux qp gnus-ml gnus-demon autocrypt-gnus nndraft nnmh gnus-topic utf-7 epa-file nnfolder bbdb-gnus bbdb-mua nnnil hydra lv winner tramp-archive tramp-gvfs zeroconf helm-x-files helm-for-files helm-external network-stream pulse image-file image-converter company-shell rpm-spec-mode company-anaconda highlight-indent-guides cap-words superword subword anaconda-mode pythonic tramp-cache time-stamp tramp-sh dired-collapse dirvish-yank dirvish-subtree dirvish-collapse dirvish-icons dirvish-vc dirvish-widgets pdf-history pdf-outline pdf-links pdf-annot pdf-sync pdf-occur tablist tablist-filter semantic/wisent/comp semantic/wisent semantic/wisent/wisent semantic/util-modes semantic/util semantic semantic/tag semantic/lex semantic/fw mode-local cedet pdf-isearch pdf-misc pdf-virtual whole-line-or-region pdf-tools package pdf-view pdf-cache pdf-info pdf-util pdf-macs generic-x skeleton generic atomic-chrome websocket minions back-button smartrep helm-projectile recentf tree-widget autorevert cus-start savehist org-edit-indirect edit-indirect org-bug bug-search bug-comment-mode bug-backend-bz-rpc bug-list-mode bug-mode bug-format bug-rpc bug-debug bug-search-common bug-common-functions bug-persistent-data bug-custom yeetube yeetube-mpv socks elfeed-autotag elfeed-score elfeed-score-maint elfeed-score-scoring elfeed-score-serde elfeed-score-rule-stats elfeed-score-rules elfeed-score-log elfeed-tube elfeed-tube-utils aio elfeed-protocol-owncloud elfeed-protocol elfeed-protocol-common elfeed-show elfeed-search rainbow-delimiters ligature symbol-overlay hideshow vc-hg vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs log-view bug-reference elfeed-csv elfeed elfeed-curl elfeed-log elfeed-db elfeed-lib xml-query emms-i18n emms-history emms-score emms-stream-info emms-metaplaylist-mode emms-bookmarks emms-cue emms-mode-line-icon emms-browser sort emms-volume emms-volume-sndioctl emms-volume-mixerctl emms-volume-pulse emms-volume-amixer emms-playlist-sort emms-last-played emms-player-mpd emms-playing-time emms-lyrics emms-url emms-player-simple emms-streams emms-show-all emms-tag-editor emms-tag-tracktag emms-info-mp3info emms-mark emms-mode-line emms-cache emms-playlist-mode emms-info-native emms-info-native-spc emms-info-native-mp3 emms-info-native-ogg emms-info-native-opus emms-info-native-flac emms-info-native-vorbis emms-info-libtag emms-info emms-later-do emms-source-playlist emms-source-file locate emms emms-compat khardel gravatar dns smiley autocrypt gnus-icalendar org-capture smtpmail-async smtpmail gnus-agent gnus-srvr gnus-score score-mode nnvirtual gnus-msg nntp gnus-cache gnus-desktop-notify bbdb-vcard bbdb-com bbdb-vcard-vcard21 bbdb bbdb-site timezone mastodon-async mastodon-tl url-cache mpv tq mastodon-iso lui-track company-emoji company-emoji-list helm-circe circe-notifications circe-display-images circe-color-nicks circe lui-irc-colors irc lcs lui-logging lui-format lui tracking shorten flyspell circe-compat ical2org org-modern org-caldav icalendar url-dav url-http url-auth url-gw nsm url-handlers ox-koma-letter ox-extra org-pomodoro alert notifications org-timer org-expiry ol-man org-clock org-protocol ob-sqlite ob-sql ob-shell ob-python python ob-plantuml ob-org ob-octave ob-lua ob-js ob-gnuplot ox-odt rng-loc rng-uri rng-parse rng-match rng-dt rng-util rng-pttrn nxml-parse nxml-ns nxml-enc xmltok nxml-util ox-latex ox-icalendar org-super-agenda ts org-habit org-duration cdlatex reftex reftex-loaddefs reftex-vars texmathp org-appear ws-butler selected jinx oc-basic ol-eww eww url-queue mm-url ol-rmail ol-mhe ol-irc ol-info ol-gnus nnselect gnus-art mm-uu mml2015 mm-view mml-smime smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group gnus-undo gnus-start gnus-dbus dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo gnus-spec gnus-int gnus-range gnus-win gnus nnheader range ol-docview doc-view ol-bibtex bibtex ol-bbdb ol-w3m ol-doi org-link-doi goto-addr view mule-util cal-china cal-bahai cal-islam cal-hebrew holidays holiday-loaddefs cal-iso cal-julian lunar solar cal-dst vim-modeline appt org-agenda ox-html table ox-ascii ox-publish ox org-element org-persist org-id org-refile org-element-ast avl-tree ob-dot ob-ditaa ob-clojure ob-C outshine outshine-org-cmds outorg smartparens-org smartparens-text smartparens loadhist org-archive-subtree-hierarchy org-archive org ob ob-tangle ob-ref ob-lob ob-table ob-exp org-macro org-src ob-comint org-pcomplete org-list org-footnote org-faces org-entities ob-emacs-lisp ob-core ob-eval org-cycle org-table ol org-fold org-fold-core org-keys oc org-loaddefs org-version org-compat org-macs noutline outline salt-mode rst mmm-jinja2 yaml-mode perl-completion woman man ffap dabbrev cperl-mode facemenu helm-elisp helm-eval edebug debug backtrace cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs ggtags ewoc flycheck-color-mode-line flycheck jka-compr let-alist meson-mode bitbake-modes bitbake autoinsert conf-bitbake-mode conf-mode bitbake-ff find-file bitbake-mmm sh-script smie treesit executable mmm-mode mmm-univ mmm-class mmm-region mmm-auto mmm-vars mmm-utils mmm-compat bitbake-functions bitbake-compat xterm-color vc-osc vc magit-libgit libgit libegit2 git-commit magit-git magit-base which-func imenu vc-git diff-mode track-changes vc-dispatcher magit-section benchmark cursor-sensor crm log-edit message sendmail yank-media puny rfc822 mml mml-sec epa epg rfc6068 epg-config gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils mailheader pcvs-util add-log diary-lib diary-loaddefs cal-menu calendar cal-loaddefs midnight vlf-setup multi-vterm company-yasnippet vterm face-remap color term disp-table ehelp vterm-module term/xterm xterm projectile ibuf-ext ibuffer ibuffer-loaddefs company-oddmuse company-keywords company-etags etags fileloop generator xref project company-gtags company-dabbrev-code company-dabbrev company-files company-clang company-capf company-cmake company-semantic company-template company-bbdb company elec-pair editorconfig editorconfig-core editorconfig-core-handle editorconfig-fnmatch wgrep-ag frames-only-mode windmove i3-integration i3 bindat marginalia which-key dirvish transient helm-dired-history dired-ranger dired-avfs dired-rainbow dired-filter dired-hacks-utils dired-x dired-async dired-du find-dired wdired dired-aux helm-icons treemacs-icons treemacs-scope treemacs-themes treemacs-core-utils treemacs-logging treemacs-customization pfuture inline hl-line treemacs-faces helm-bookmark helm-net browse-url xml url url-proxy url-privacy url-expand url-methods url-history url-cookie url-domsuf url-util mailcap helm-adaptive helm-info bookmark helm-mode helm-misc helm-files image-dired image-dired-tags image-dired-external image-dired-util image-mode dired dired-loaddefs exif filenotify tramp trampver tramp-integration files-x tramp-message tramp-compat xdg parse-time iso8601 time-date tramp-loaddefs helm-buffers all-the-icons all-the-icons-faces data-material data-weathericons data-octicons data-fileicons data-faicons data-alltheicons helm-occur helm-tags helm-locate helm-grep wgrep-helm wgrep grep compile text-property-search helm-regexp format-spec helm-utils helm-help helm-types so-long emojify apropos tar-mode arc-mode archive-mode ht cursor-chg doom-modeline doom-modeline-segments doom-modeline-env doom-modeline-core shrink-path f s dash nerd-icons nerd-icons-faces nerd-icons-data nerd-icons-data-mdicon nerd-icons-data-flicon nerd-icons-data-codicon nerd-icons-data-devicon nerd-icons-data-sucicon nerd-icons-data-wicon nerd-icons-data-faicon nerd-icons-data-powerline nerd-icons-data-octicon nerd-icons-data-pomicon nerd-icons-data-ipsicon modus-vivendi-theme modus-themes helm-pass password-store with-editor shell pcomplete comint ansi-osc ansi-color ring server helm helm-global-bindings helm-easymenu edmacro kmacro helm-core async-bytecomp helm-source helm-multi-match helm-lib async auth-source-pass url-parse url-vars auth-source password-cache printing ps-print ps-print-loaddefs lpr desktop frameset derived advice info+ thingatpt cl saveplace delsel no-littering epkg-elpa json map epkg-utils epkg-list epkg-desc find-func epkg closql emacsql-sqlite-common emacsql emacsql-compiler eieio-base eieio byte-opt eieio-core cl-macs llama comp-run compat use-package use-package-ensure use-package-delight use-package-diminish use-package-bind-key bind-key easy-mmode use-package-core zop-to-char-autoloads yeetube-autoloads yasnippet-autoloads yaml-mode-autoloads yaml-autoloads xterm-color-autoloads ws-butler-autoloads with-editor-autoloads whole-line-or-region-autoloads which-key-autoloads wgrep-autoloads websocket-autoloads web-mode-autoloads w3m-autoloads vlf-autoloads visual-regexp-autoloads vim-modeline-autoloads vc-osc-autoloads uuidgen-autoloads use-package-autoloads ts-autoloads treepy-autoloads treemacs-nerd-icons-autoloads treemacs-autoloads transient-autoloads toml-mode-autoloads systemd-autoloads symbol-overlay-autoloads swiper-helm-autoloads ssh-config-mode-autoloads spinner-autoloads smartrep-autoloads smartparens-autoloads smart-region-autoloads skewer-mode-autoloads simple-httpd-autoloads shrink-path-autoloads selected-autoloads salt-mode-autoloads s-autoloads rpm-spec-mode-autoloads rich-minority-autoloads request-autoloads rainbow-delimiters-autoloads qt-pro-mode-autoloads qml-mode-autoloads pythonic-autoloads projectile-autoloads posframe-autoloads pos-tip-autoloads popup-autoloads plantuml-mode-autoloads pkgbuild-mode-autoloads piper-autoloads pfuture-autoloads perspective-autoloads persp-mode-autoloads persist-autoloads password-store-autoloads pass-autoloads outshine-autoloads outorg-autoloads orgit-forge-autoloads orgit-autoloads org-vcard-autoloads org-tree-slide-autoloads org-super-agenda-autoloads org-pomodoro-autoloads org-modern-autoloads org-edit-indirect-autoloads org-contrib-autoloads org-contacts-autoloads org-clock-helpers-autoloads org-caldav-autoloads org-appear-autoloads org-autoloads no-littering-autoloads nginx-mode-autoloads nerd-icons-ibuffer-autoloads nerd-icons-autoloads navi-mode-autoloads multiple-cursors-autoloads multi-vterm-autoloads mpv-autoloads move-text-autoloads modus-themes-autoloads mode-icons-autoloads mmm-mode-autoloads mmm-jinja2-autoloads minions-autoloads message-x-autoloads message-view-patch-autoloads message-attachment-reminder-autoloads meson-mode-autoloads mastodon-autoloads markdown-mode-autoloads marginalia-autoloads magit-popup-autoloads magit-autoloads lua-mode-autoloads lsp-ui-autoloads lsp-treemacs-autoloads lsp-mode-autoloads lsp-docker-autoloads logview-autoloads llama-autoloads lisp-autoloads link-hint-autoloads ligature-autoloads levenshtein-autoloads khardel-autoloads js2-mode-autoloads journalctl-autoloads jira-markup-mode-autoloads ivy-autoloads irony-autoloads ir-black-theme-autoloads info+-autoloads iedit-autoloads ical2org-autoloads ibuffer-projectile-autoloads i3wm-config-mode-autoloads i3-autoloads hydra-autoloads htmlize-autoloads ht-autoloads highlight-indent-guides-autoloads helm-projectile-autoloads helm-pass-autoloads helm-org-rifle-autoloads helm-make-autoloads helm-ls-git-autoloads helm-icons-autoloads helm-ext-autoloads helm-emms-autoloads helm-dired-history-autoloads helm-descbinds-autoloads helm-circe-autoloads helm-autoloads guess-language-autoloads grep-context-autoloads goto-chg-autoloads gnus-recent-autoloads gnus-notes-autoloads gnus-desktop-notify-autoloads gnus-alias-autoloads gitconfig-autoloads git-modes-autoloads ghub-autoloads ggtags-autoloads frames-only-mode-autoloads forge-autoloads flycheck-color-mode-line-autoloads flycheck-autoloads fedi-autoloads f-autoloads extmap-autoloads expand-region-autoloads evil-multiedit-autoloads evil-autoloads emojify-autoloads emacsql-autoloads elixir-mode-autoloads elfeed-tube-autoloads elfeed-summary-autoloads elfeed-score-autoloads elfeed-protocol-autoloads elfeed-autotag-autoloads elfeed-autoloads el-mock-autoloads eimp-autoloads editorconfig-autoloads edit-indirect-autoloads dumb-jump-autoloads doom-modeline-autoloads docbook-autoloads dirvish-autoloads dired-rsync-autoloads dired-hacks-autoloads dired-du-autoloads devhelp-autoloads deferred-autoloads default-text-scale-autoloads debbugs-autoloads datetime-autoloads dash-autoloads dap-mode-autoloads cursor-chg-autoloads crux-autoloads copy-as-format-autoloads compat-autoloads company-shell-autoloads company-quickhelp-autoloads company-nginx-autoloads company-lua-autoloads company-irony-autoloads company-emoji-autoloads company-anaconda-autoloads company-autoloads code-review-autoloads cmake-mode-autoloads cmake-font-lock-autoloads closql-autoloads circe-notifications-autoloads circe-autoloads cdlatex-autoloads ccls-autoloads buttercup-autoloads bui-autoloads bug-mode-autoloads bitbake-modes-autoloads bbdb-vcard-autoloads bbdb-loaddefs back-button-autoloads avy-autoloads autocrypt-autoloads auto-compile-autoloads atomic-chrome-autoloads async-autoloads anaconda-mode-autoloads all-the-icons-autoloads alert-autoloads aio-autoloads ag-autoloads ace-window-autoloads ace-link-autoloads a-autoloads 2048-game-autoloads borg loaddefs-gen generate-lisp-file lisp-mnt radix-tree info cus-edit pp pcase cus-load wid-edit comp cl-seq comp-cstr cl-extra help-mode comp-common warnings icons subr-x rx gv cl-loaddefs cl-lib bytecomp byte-compile preview-latex auctex tex-site ispell rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads xwidget-internal dbusbind inotify lcms2 dynamic-setting system-font-setting font-render-setting cairo gtk x-toolkit xinput2 x multi-tty move-toolbar make-network-process native-compile emacs) Memory information: ((conses 16 8814971 1834230) (symbols 48 113156 6) (strings 32 2138810 377553) (string-bytes 1 196033441) (vectors 16 420969) (vector-slots 8 7713005 1814464) (floats 8 10276 45198) (intervals 56 524388 35453) (buffers 992 455)) ^ permalink raw reply [flat|nested] 6+ messages in thread
* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true 2024-08-03 11:12 bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-08-09 18:02 ` J.P. 2024-08-09 19:20 ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors [not found] ` <87ed6xy03r.fsf@> 0 siblings, 2 replies; 6+ messages in thread From: J.P. @ 2024-08-09 18:02 UTC (permalink / raw) To: 72441; +Cc: Björn Bidar [-- Attachment #1: Type: text/plain, Size: 8474 bytes --] Björn Bidar via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> writes: > I noticed that auth-source-pass doesn't match agains password file > attributes such as those containing :user and only matches password > files which contain a host and a user when > auth-source-pass-extra-query-keywords is true. I don't use pass myself, nor have I ever, but I suppose I did add the `auth-source-pass-extra-query-keywords' option (though mainly in a bid to make auth-source-pass behave more like other back ends so it's usable with ERC). Anyway, I do actually recall being somewhat aware of the existence of the file attributes you mention. It seems I even left a comment about the current lack of support [1]. Looking into this a bit, it seems the password store's web page considers everything after the initial (password) line to be an opaque text blob: The password store does not impose any particular schema or type of organization of your data, as it is simply a flat text file, which can contain arbitrary data. Though the most common case is storing a single password per entry, some power users find they would like to store more than just their password inside the password store, and additionally store answers to secret questions, website URLs, and other sensitive information or metadata. Since the password store does not impose a scheme of it's own, you can choose your own organization. There are many possibilities. However, I do realize that the auth-source-pass back end without the extra-keywords option already dips into a file's contents looking for an attributes list like the one shown on the web page. (Whether that's wise is pretty much moot after all these years.) Anyway, for that reason, I suppose we _should_ attempt to at least explore doing the same when the extra-keywords option is enabled. For me, the most important thing remains mimicking the behavior of the other built-in back ends, which at times is admittedly unintuitive but nevertheless consistent and thus predictable from a mechanical POV. > Steps to reproduce: > 1. Setup pass with the following structure > WorkingTest/example.com/foo > FailingTest/example2.com > FailingTest/example3.com with user: foo in the password file > 2. (auth-source-pass-enable) > 3. (setq auth-source-pass-extra-query-keywords t) > 4. (auth-source-search :host "example" :user "foo") -> works > 5. (auth-source-search :host "example2.com") -> fails > 6. (auth-source-search :host "example3.com" :user "foo") > > Auth-source-pass should be able to query the password file for > additional attributes if one of the previous attributes such as :host > match to it. Quering the file attributes is quite important in use > cases where it doesn't make sense to the user to have a > host-folder/user-file structure in cases where there's only one > password for said host. Currently, if you have a file in the root of your ~/.password-store named something like "top-level-host.com", and it's contents feature a "user: foo" attribute, both (auth-source-search :host "top-level-host.com") and (auth-source-search :host "top-level-host.com" :user "foo") return ((:host "top-level-host.com" :secret ...)). If you're saying you want to see (:user "foo") in the results as well, I guess we can do that (see attached patch as well as [2], below). However, this still won't work on any of your examples, which all have intervening path components between the root directory and the .gpg files. The reason for this restriction is explained below. If we do end up going with something like the attached patch, we'll need to profile it. I can create a bunch of fake trees of varying shapes and sizes, but I'd rather someone with real data and a sizable store assess how much slower it is to visit (and thus decrypt) potentially every file in the tree, which is what any attr-reading implementation must do. On my machine, it takes roughly 0.18 seconds to decrypt a single two-line file via `auth-source-pass--read-entry'. (This seems prohibitively expensive to do en masse, no?) FWIW, most of this time is spent in `epg-wait-for-status', which blocks until the subprocess exits. > Same it should maybe also match against :host > if no user was provided, I don't know how other sources do this thou. While the reference implementation indeed succeeds with a plain :host input (see test `auth-source-pass-extra-query-keywords--netrc-host'), I believe the actual problem you perceive has more to do with the content of the file paths, specifically, leading directory components. Still, I'm inclined to agree that this would be nice to have. However, I do seem to recall this being discussed on at least one occasion, with the conclusion being that it's too complicated, if not impossible, to disambiguate between a trailing "hostname/user" and "folder/hostname". Nevertheless, we could add an option to do it anyway based on one or more heuristics-based strategy (resolving hosts for real is surely a no go). For example, one such strategy could ignore a penultimate file-path component that's not an FQDN, even if it's, say, LDH-only and resolvable as a hostname, so long as the leaf component _is_ an FQDN. However, such an option would have to be disabled by default to prevent existing entries like "localhost/test.user" from being parsed as (:host "test.user"). In any case, I'm happy to review patches, but I think someone who actually uses this back end should implement the feature. [1] https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/auth-source-pass.el?id=423c86cb#n300 [2] The following describes details of the attached patch's logic for the inner (dolist (e entries) ...) loop of the primary matching function `auth-source-pass--find-match-many'. Hopefully it's somewhat sound with regard to deferring decryption for as long as possible. 1. Parse the file path of each entry first and cache its results in a plist, the "cached entry metadata," which is filed under the entry's file-path in the `seen' hash table. If it doesn't match the basic filename format, it must not be a passwordstore file, so reject the entry. 2. Check the :host field before reading the file. Unless it matches, reject the entry. 3. Engage in a series of probing conditional checks for a :port field to match against a provided "port" query parameter, all while attempting to defer decryption until absolutely necessary. (A path-encoded :port always takes precedence over a :port in the file.) - If a `port' query parameter is not given for matching against, continue to the next steps for the current entry. - Otherwise, if a :port parsed from the file path is present and it doesn't match, reject the entry, meaning go to the beginning of the current loop, considering the next entry. - If a path-derived :port is absent, ensure the cached entry metadata contains an additional :attrs field (an alist). If the metadata lacks an :attrs field, the file has not yet been decrypted. Decrypt it now using `auth-source-pass-parse-entry', then add its secret and its attrs alist to the cached metadata, under :attrs. - Look in the cached entry metadata's :attrs alist for a "port" attr. If a "port" attr is indeed present and doesn't match the port query parameter, reject the entry. - If no such "port" attr exists and is required (meaning :port appears in the `require' query parameter), reject the entry. 4. Repeat step 3 for :user. The same precedence rules apply, meaning any non-null path-derived :user field is immediately accepted, and the file is not decrypted. 5. If we haven't yet decrypted the file, do so now and populate the :attrs item in the cached entry metadata. If it's already been decrypted at some point, :attrs will present (though possibly empty). In any case, add the items we care about if non-null (:user, :port, and :secret) to the matched results for this entry. However, only do so if a secret was either not required or is present; otherwise, reject the entry. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-POC-Match-attrs-with-auth-source-pass-extra-query-ke.patch --] [-- Type: text/x-patch, Size: 13646 bytes --] From a36ef10d81e2c5afb0cf2515887084b6331d38d1 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Wed, 7 Aug 2024 22:23:09 -0700 Subject: [PATCH] [POC] Match attrs with auth-source-pass-extra-query-keywords * lisp/auth-source-pass.el (auth-source-pass--retrieve-parsed): Remove unused function. (auth-source-pass--cast-port): New function, a helper to match an entry's port to the given query param's type. (auth-source-pass--match-parts): Return non-nil when a key is required but the value is null. Not doing produced behavior that deviated from the reference netrc implementation and was thus a bug. (auth-source-pass-check-attrs-with-extra-query-keywords): New variable, a flag to opt out of arguably expensive attribute lookups. (auth-source-pass--find-matched-entry): New function to isolate processing logic for a single entry. (auth-source-pass--find-match-many): Move single-entry processing logic to separate helper, mainly for readability. * test/lisp/auth-source-pass-tests.el (auth-source-pass-extra-query-keywords--akib/attr) (auth-source-pass-extra-query-keywords--netrc-akib/require) (auth-source-pass-extra-query-keywords--akib/attr/require) (auth-source-pass-extra-query-keywords--netrc-baseline): New tests. (auth-source-pass-extra-query-keywords--baseline): Reverse expected outcome to match reference implementation. That it didn't before was a bug. (Bug#72441) --- lisp/auth-source-pass.el | 130 +++++++++++++++++++--------- test/lisp/auth-source-pass-tests.el | 79 ++++++++++++++++- 2 files changed, 165 insertions(+), 44 deletions(-) diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 03fd1f35811..8982e07a6be 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -256,32 +256,88 @@ auth-source-pass--find-match hosts (list hosts)))) -(defun auth-source-pass--retrieve-parsed (seen path port-number-p) - (when (string-match auth-source-pass--match-regexp path) - (puthash path - `( :host ,(or (match-string 10 path) (match-string 11 path)) - ,@(if-let* ((tr (match-string 21 path))) - (list :user tr :suffix t) - (list :user (match-string 20 path))) - :port ,(and-let* ((p (or (match-string 30 path) - (match-string 31 path))) - (n (string-to-number p))) - (if (or (zerop n) (not port-number-p)) - (format "%s" p) - n))) - seen))) - -(defun auth-source-pass--match-parts (parts key value require) - (let ((mv (plist-get parts key))) +(defun auth-source-pass--cast-port (val ref) + (cond ((integerp val) val) + ((and-let* (((integerp ref)) + (n (string-to-number val)) + ((not (zerop n)))) + n)) + (t (format "%s" val)))) + +(defun auth-source-pass--match-parts (parts key reference require) + (let ((value (plist-get parts key))) (if (memq key require) - (and value (equal mv value)) - (or (not value) (not mv) (equal mv value))))) + (or (null reference) (equal value reference)) + (or (null reference) (null value) (equal value reference))))) + +(defvar auth-source-pass-check-attrs-with-extra-query-keywords t + "When non-nil, decrypt files to find attributes matching parameters. +However, give precedence to fields encoded in file names. Only applies +when `auth-source-pass-extra-query-keywords' is non-nil.") + +;; This function tries to defer decryption as long as possible. For +;; that reason, an entry's file-path-derived :port or :user field +;; always takes precedence over their counterparts from a decrypted +;; file's attribute list. +(defun auth-source-pass--find-matched-entry (host user port require seen entry) + "Match ENTRY against query params HOST USER PORT REQUIRE with cache SEEN." + (when (string-match auth-source-pass--match-regexp entry) + (let* ((cached (gethash entry seen)) + (optp auth-source-pass-check-attrs-with-extra-query-keywords) + (suffixedp nil) + (h (or (and cached (plist-get cached :host)) + (match-string 10 entry) + (match-string 11 entry))) + (attrs (and cached (plist-get :attrs cached))) + (getat (lambda (k) + (save-match-data + (unless attrs + (setq attrs (auth-source-pass-parse-entry entry))) + (auth-source-pass--get-attr k attrs)))) + (u (cond (cached (plist-get cached :user)) + ((and-let* ((u (match-string 21 entry))) + (setq suffixedp t) + u)) + ((match-string 20 entry)) + ((and user optp) (funcall getat "user")))) + (p (cond (cached (plist-get cached :port)) + ((match-string 30 entry)) + ((match-string 31 entry)) + ((and port optp) (funcall getat "port")))) + ;; + s) + (when p + (setq p (auth-source-pass--cast-port p port))) + (unless cached + (setq cached `( :host ,h + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and suffixedp (list :suffix t)) + ,@(and attrs (list :attrs attrs)))) + (puthash entry cached seen)) + (when (and (equal host h) + (auth-source-pass--match-parts cached :port port require) + (auth-source-pass--match-parts cached :user user require) + (setq s (or (funcall getat 'secret) + (not (memq :secret require))))) + (unless (or user u) + (when (setq u (funcall getat "user")) + (setq cached (plist-put cached :user u)))) + (unless (or port p) + (when (setq p (funcall getat "port")) + (setq p (auth-source-pass--cast-port p port) + cached (plist-put cached :port p)))) + (puthash entry (plist-put cached :attrs attrs) seen) + `( :host ,host + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and s (not (eq s t)) (list :secret s))))))) (defun auth-source-pass--find-match-many (hosts users ports require max) "Return plists for valid combinations of HOSTS, USERS, PORTS." (let ((seen (make-hash-table :test #'equal)) (entries (auth-source-pass-entries)) - out suffixed suffixedp) + out suffixed) (catch 'done (dolist (host hosts out) (pcase-let ((`(,_ ,u ,p) (auth-source-pass--disambiguate host))) @@ -289,28 +345,18 @@ auth-source-pass--find-match-many (setq p nil)) (dolist (user (or users (list u))) (dolist (port (or ports (list p))) - (dolist (e entries) - (when-let* - ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed - seen e (integerp port)))) - ((equal host (plist-get m :host))) - ((auth-source-pass--match-parts m :port port require)) - ((auth-source-pass--match-parts m :user user require)) - (parsed (auth-source-pass-parse-entry e)) - ;; For now, ignore body-content pairs, if any, - ;; from `auth-source-pass--parse-data'. - (secret (or (auth-source-pass--get-attr 'secret parsed) - (not (memq :secret require))))) - (push - `( :host ,host ; prefer user-provided :host over h - ,@(and-let* ((u (plist-get m :user))) (list :user u)) - ,@(and-let* ((p (plist-get m :port))) (list :port p)) - ,@(and secret (not (eq secret t)) (list :secret secret))) - (if (setq suffixedp (plist-get m :suffix)) suffixed out)) - (unless suffixedp - (when (or (zerop (cl-decf max)) - (null (setq entries (delete e entries)))) - (throw 'done out))))) + (dolist (entry entries) + (let* ((result (auth-source-pass--find-matched-entry + host user port require seen entry)) + ;; + suffixedp) + (when result + (setq suffixedp (plist-get (gethash entry seen) :suffix)) + (push result (if suffixedp suffixed out)) + (unless suffixedp + (when (or (zerop (cl-decf max)) + (null (setq entries (delete entry entries)))) + (throw 'done out)))))) (setq suffixed (nreverse suffixed)) (while suffixed (push (pop suffixed) out) diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 6455c3393d5..2ce5d12a6bc 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -601,6 +601,73 @@ auth-source-pass-extra-query-keywords--akib (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") ("port" . "42")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + results) + + ;; Non-matching query param. + (setq results (auth-source-search :host "disroot.org" :user "?" :max 2)) + (should-not results) + + ;; No query params matching attrs. + (setq results (auth-source-search :host "disroot.org" :max 2)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching user query param. + (setq results (auth-source-search :host "disroot.org" :user "akib")) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching port typed query param. + (setq results (auth-source-search :host "disroot.org" :port 42)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port 42 :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--netrc-akib/require () + (ert-with-temp-file netrc-file + :text "\ +machine x.com password a +machine disroot.org user akib password b +machine z.com password c +" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "disroot.org" + :require '(:user) :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/require () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" + :require '(:user) :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :secret "b"))))))) + ;; Searches for :host are case-sensitive, and a returned host isn't ;; normalized. @@ -632,11 +699,19 @@ auth-source-pass-extra-query-keywords--host ;; A retrieved store entry mustn't be nil regardless of whether its ;; path contains port or user components. +(ert-deftest auth-source-pass-extra-query-keywords--netrc-baseline () + (ert-with-temp-file netrc-file + :text "machine foo\n" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "foo"))) + (should (equal results '((:host "foo"))))))) + (ert-deftest auth-source-pass-extra-query-keywords--baseline () (let ((auth-source-pass-extra-query-keywords t)) - (auth-source-pass--with-store '(("x.com")) + (auth-source-pass--with-store '(("foo")) (auth-source-pass-enable) - (should-not (auth-source-search :host "x.com"))))) + (should (equal (auth-source-search :host "foo") '((:host "foo"))))))) ;; Output port type (int or string) matches that of input parameter. -- 2.45.2 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true 2024-08-09 18:02 ` J.P. @ 2024-08-09 19:20 ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors [not found] ` <87ed6xy03r.fsf@> 1 sibling, 0 replies; 6+ messages in thread From: Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-08-09 19:20 UTC (permalink / raw) To: J.P.; +Cc: 72441 "J.P." <jp@neverwas.me> writes: > Björn Bidar via "Bug reports for GNU Emacs, the Swiss army knife of text > editors" <bug-gnu-emacs@gnu.org> writes: > >> I noticed that auth-source-pass doesn't match agains password file >> attributes such as those containing :user and only matches password >> files which contain a host and a user when >> auth-source-pass-extra-query-keywords is true. > > I don't use pass myself, nor have I ever, but I suppose I did add the > `auth-source-pass-extra-query-keywords' option (though mainly in a bid > to make auth-source-pass behave more like other back ends so it's usable > with ERC). Anyway, I do actually recall being somewhat aware of the > existence of the file attributes you mention. It seems I even left a > comment about the current lack of support [1]. I started using the option since my girlfriends password store is organized for many passwords as hostname.tld/user@exampl.com, when she created a password that is <Topic e.g. SSO>/example.com/user where without the option the wrong password files were used. Her mail address is user@example.com and the login server is also example.com with her name as the username (we selfhost). > Looking into this a bit, it seems the password store's web page > considers everything after the initial (password) line to be an opaque > text blob: > > The password store does not impose any particular schema or type of > organization of your data, as it is simply a flat text file, which can > contain arbitrary data. Though the most common case is storing a > single password per entry, some power users find they would like to > store more than just their password inside the password store, and > additionally store answers to secret questions, website URLs, and > other sensitive information or metadata. Since the password store does > not impose a scheme of it's own, you can choose your own organization. > There are many possibilities. > > However, I do realize that the auth-source-pass back end without the > extra-keywords option already dips into a file's contents looking for an > attributes list like the one shown on the web page. (Whether that's wise > is pretty much moot after all these years.) Anyway, for that reason, I > suppose we _should_ attempt to at least explore doing the same when the > extra-keywords option is enabled. For me, the most important thing > remains mimicking the behavior of the other built-in back ends, which at > times is admittedly unintuitive but nevertheless consistent and thus > predictable from a mechanical POV. I agree fully with the comment. Other's that use pass as source for passwords also use file contents to match or retrieve variables from. E.g. most browser plugins derive the parameter for the login or user name from either of these names. >> Steps to reproduce: >> 1. Setup pass with the following structure >> WorkingTest/example.com/foo >> FailingTest/example2.com >> FailingTest/example3.com with user: foo in the password file >> 2. (auth-source-pass-enable) >> 3. (setq auth-source-pass-extra-query-keywords t) >> 4. (auth-source-search :host "example" :user "foo") -> works >> 5. (auth-source-search :host "example2.com") -> fails >> 6. (auth-source-search :host "example3.com" :user "foo") >> >> Auth-source-pass should be able to query the password file for >> additional attributes if one of the previous attributes such as :host >> match to it. Quering the file attributes is quite important in use >> cases where it doesn't make sense to the user to have a >> host-folder/user-file structure in cases where there's only one >> password for said host. > > Currently, if you have a file in the root of your ~/.password-store > named something like "top-level-host.com", and it's contents feature a > "user: foo" attribute, both > > (auth-source-search :host "top-level-host.com") > > and > > (auth-source-search :host "top-level-host.com" :user "foo") > > return > > ((:host "top-level-host.com" :secret ...)). > > If you're saying you want to see (:user "foo") in the results as well, I > guess we can do that (see attached patch as well as [2], below). > However, this still won't work on any of your examples, which all have > intervening path components between the root directory and the .gpg > files. The reason for this restriction is explained below. > > If we do end up going with something like the attached patch, we'll need > to profile it. I can create a bunch of fake trees of varying shapes and > sizes, but I'd rather someone with real data and a sizable store assess > how much slower it is to visit (and thus decrypt) potentially every file > in the tree, which is what any attr-reading implementation must do. On > my machine, it takes roughly 0.18 seconds to decrypt a single two-line > file via `auth-source-pass--read-entry'. (This seems prohibitively > expensive to do en masse, no?) FWIW, most of this time is spent in > `epg-wait-for-status', which blocks until the subprocess exits. That is why I was arguing that we should attempt to not try decrypt the password file unless a previous attribute such as :host or :user matched before. If we could do the search in parallel or at least without blocking Emacs that would be a different story of course. >> Same it should maybe also match against :host >> if no user was provided, I don't know how other sources do this thou. > > While the reference implementation indeed succeeds with a plain :host > input (see test `auth-source-pass-extra-query-keywords--netrc-host'), I > believe the actual problem you perceive has more to do with the content > of the file paths, specifically, leading directory components. Still, > I'm inclined to agree that this would be nice to have. However, I do > seem to recall this being discussed on at least one occasion, with the > conclusion being that it's too complicated, if not impossible, to > disambiguate between a trailing "hostname/user" and "folder/hostname". > > Nevertheless, we could add an option to do it anyway based on one or > more heuristics-based strategy (resolving hosts for real is surely a no > go). For example, one such strategy could ignore a penultimate file-path > component that's not an FQDN, even if it's, say, LDH-only and resolvable > as a hostname, so long as the leaf component _is_ an FQDN. However, such > an option would have to be disabled by default to prevent existing > entries like "localhost/test.user" from being parsed as (:host > "test.user"). > What do you mean by resolving hosts for real? I think another option would be for the user to specific the hierarchy of their password store to auth-source-pass e.g. word/%host%/%user or word/(or %host word)/%user where word is any word that isn't used for matching but just for the user to organize the hierarchy. > In any case, I'm happy to review patches, but I think someone who > actually uses this back end should implement the feature. I'm not a good lisp programmar but I could give it a go with some help such as your patch as a start point. > > [1] https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/auth-source-pass.el?id=423c86cb#n300 > > [2] The following describes details of the attached patch's logic for > the inner (dolist (e entries) ...) loop of the primary matching > function `auth-source-pass--find-match-many'. Hopefully it's > somewhat sound with regard to deferring decryption for as long as > possible. > > 1. Parse the file path of each entry first and cache its results in > a plist, the "cached entry metadata," which is filed under the > entry's file-path in the `seen' hash table. If it doesn't match > the basic filename format, it must not be a passwordstore file, > so reject the entry. > 2. Check the :host field before reading the file. Unless it matches, > reject the entry. > 3. Engage in a series of probing conditional checks for a :port > field to match against a provided "port" query parameter, all > while attempting to defer decryption until absolutely necessary. > (A path-encoded :port always takes precedence over a :port in the > file.) > - If a `port' query parameter is not given for matching against, > continue to the next steps for the current entry. > - Otherwise, if a :port parsed from the file path is present and > it doesn't match, reject the entry, meaning go to the beginning > of the current loop, considering the next entry. > - If a path-derived :port is absent, ensure the cached entry > metadata contains an additional :attrs field (an alist). If the > metadata lacks an :attrs field, the file has not yet been > decrypted. Decrypt it now using `auth-source-pass-parse-entry', > then add its secret and its attrs alist to the cached metadata, > under :attrs. > - Look in the cached entry metadata's :attrs alist for a "port" > attr. If a "port" attr is indeed present and doesn't match the > port query parameter, reject the entry. > - If no such "port" attr exists and is required (meaning :port > appears in the `require' query parameter), reject the entry. > 4. Repeat step 3 for :user. The same precedence rules apply, meaning > any non-null path-derived :user field is immediately accepted, > and the file is not decrypted. > 5. If we haven't yet decrypted the file, do so now and populate the > :attrs item in the cached entry metadata. If it's already been > decrypted at some point, :attrs will present (though possibly > empty). In any case, add the items we care about if non-null > (:user, :port, and :secret) to the matched results for this entry. > However, only do so if a secret was either not required or is > present; otherwise, reject the entry. ^ permalink raw reply [flat|nested] 6+ messages in thread
[parent not found: <87ed6xy03r.fsf@>]
* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true [not found] ` <87ed6xy03r.fsf@> @ 2024-08-10 13:58 ` J.P. 2024-08-12 19:33 ` J.P. 0 siblings, 1 reply; 6+ messages in thread From: J.P. @ 2024-08-10 13:58 UTC (permalink / raw) To: Björn Bidar; +Cc: 72441 [-- Attachment #1: Type: text/plain, Size: 6077 bytes --] Björn Bidar <bjorn.bidar@thaodan.de> writes: > "J.P." <jp@neverwas.me> writes: > >> However, I do realize that the auth-source-pass back end without the >> extra-keywords option already dips into a file's contents looking for an >> attributes list like the one shown on the web page. (Whether that's wise >> is pretty much moot after all these years.) Anyway, for that reason, I >> suppose we _should_ attempt to at least explore doing the same when the >> extra-keywords option is enabled. For me, the most important thing >> remains mimicking the behavior of the other built-in back ends, which at >> times is admittedly unintuitive but nevertheless consistent and thus >> predictable from a mechanical POV. > > I agree fully with the comment. Other's that use pass as source for > passwords also use file contents to match or retrieve variables from. > E.g. most browser plugins derive the parameter for the login or user > name from either of these names. Hm, actually, I was not initially thinking of including all the attributes, only :user and :port. But it seems I'd forgotten that the netrc reference implementation does indeed include arbitrary key/value pairs in the results from a successful match: # ~/.authinfo machine example.org login me password 123 foo bar M-: (auth-source-search :host "example.org") => (... :foo "bar") I've updated my previous patch to do this. >> If we do end up going with something like the attached patch, we'll need >> to profile it. I can create a bunch of fake trees of varying shapes and >> sizes, but I'd rather someone with real data and a sizable store assess >> how much slower it is to visit (and thus decrypt) potentially every file >> in the tree, which is what any attr-reading implementation must do. On >> my machine, it takes roughly 0.18 seconds to decrypt a single two-line >> file via `auth-source-pass--read-entry'. (This seems prohibitively >> expensive to do en masse, no?) FWIW, most of this time is spent in >> `epg-wait-for-status', which blocks until the subprocess exits. > > That is why I was arguing that we should attempt to not try decrypt the > password file unless a previous attribute such as :host or :user matched > before. > If we could do the search in parallel or at least without blocking Emacs > that would be a different story of course. With what I'm proposing, we would actually decrypt to inspect the parsed attrs if :port or :user isn't found in the filename and a port or user query parameter is given (or :port or :user appears in a :require parameter). This behavior is currently gated by a new variable called `auth-source-pass-check-attrs-with-extra-query-keywords', but it's t by default. Perhaps it's better to have it be nil? If we do that, then, by default, :port and :user attributes won't be considered, but they will still be included in successful matches along with all other attributes. >>> Same it should maybe also match against :host >>> if no user was provided, I don't know how other sources do this thou. >> >> While the reference implementation indeed succeeds with a plain :host >> input (see test `auth-source-pass-extra-query-keywords--netrc-host'), I >> believe the actual problem you perceive has more to do with the content >> of the file paths, specifically, leading directory components. Still, >> I'm inclined to agree that this would be nice to have. However, I do >> seem to recall this being discussed on at least one occasion, with the >> conclusion being that it's too complicated, if not impossible, to >> disambiguate between a trailing "hostname/user" and "folder/hostname". >> >> Nevertheless, we could add an option to do it anyway based on one or >> more heuristics-based strategy (resolving hosts for real is surely a no >> go). For example, one such strategy could ignore a penultimate file-path >> component that's not an FQDN, even if it's, say, LDH-only and resolvable >> as a hostname, so long as the leaf component _is_ an FQDN. However, such >> an option would have to be disabled by default to prevent existing >> entries like "localhost/test.user" from being parsed as (:host >> "test.user"). >> > > What do you mean by resolving hosts for real? I just meant it'd be unrealistic to query the system resolver via `network-lookup-address-info' or similar whenever we need to disambiguate. > I think another option would be for the user to specific the hierarchy > of their password store to auth-source-pass e.g. word/%host%/%user or > word/(or %host word)/%user where word is any word that isn't used for > matching but just for the user to organize the hierarchy. That could work, although it seems rather complex with pattern substitutions and expressions (?). Perhaps it could be precomputed somehow into a regexp before every query. Another idea would be to just have the option be an integer indicating the number of leading path components to mask off before matching. Given a tree like ~/.password-store/ - foo/ - example.com - irc.bar.org/ - example.net/ - me - baz/ - myvps/ - my.user.name if the option (which is 0 by default) were set to 1, then possible results might be (:host "example.com" :user "some-attr") (:host "example.net" :user "me") (:host "myvps" :user "my.user.name") Although this won't work if a user wants different mask depths for different sub-directories. >> In any case, I'm happy to review patches, but I think someone who >> actually uses this back end should implement the feature. > > I'm not a good lisp programmar but I could give it a go with some help > such as your patch as a start point. I should be able to handle the attribute feature, unless you want to improve upon it. It's mainly the disambiguation feature that I'd want an actual pass user, like yourself, to implement or at least help design. (Although feel free to offer patches of any nature, including based on anything I've proposed.) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0000-v1-v2.diff --] [-- Type: text/x-patch, Size: 5153 bytes --] From a0381a48cb4ff960ef2dd55dd511f5c18e535f6e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Sat, 10 Aug 2024 07:15:36 -0700 Subject: [PATCH 0/1] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (1): [POC] Match attrs with auth-source-pass-extra-query-keywords lisp/auth-source-pass.el | 143 ++++++++++++++++++++-------- test/lisp/auth-source-pass-tests.el | 96 ++++++++++++++++++- 2 files changed, 195 insertions(+), 44 deletions(-) Interdiff: diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 8982e07a6be..0df7817f501 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -264,10 +264,10 @@ auth-source-pass--cast-port n)) (t (format "%s" val)))) -(defun auth-source-pass--match-parts (parts key reference require) - (let ((value (plist-get parts key))) +(defun auth-source-pass--match-parts (cache key reference require) + (let ((value (plist-get cache key))) (if (memq key require) - (or (null reference) (equal value reference)) + (if reference (equal value reference) value) (or (null reference) (null value) (equal value reference))))) (defvar auth-source-pass-check-attrs-with-extra-query-keywords t @@ -299,13 +299,15 @@ auth-source-pass--find-matched-entry (setq suffixedp t) u)) ((match-string 20 entry)) - ((and user optp) (funcall getat "user")))) + ((and optp (or user (memq :user require))) + (funcall getat "user")))) (p (cond (cached (plist-get cached :port)) ((match-string 30 entry)) ((match-string 31 entry)) - ((and port optp) (funcall getat "port")))) + ((and optp (or port (memq :port require))) + (funcall getat "port")))) ;; - s) + s extras) (when p (setq p (auth-source-pass--cast-port p port))) (unless cached @@ -320,18 +322,29 @@ auth-source-pass--find-matched-entry (auth-source-pass--match-parts cached :user user require) (setq s (or (funcall getat 'secret) (not (memq :secret require))))) - (unless (or user u) - (when (setq u (funcall getat "user")) - (setq cached (plist-put cached :user u)))) - (unless (or port p) - (when (setq p (funcall getat "port")) - (setq p (auth-source-pass--cast-port p port) - cached (plist-put cached :port p)))) + (let (tmp) + (while-let ((v (pop attrs)) + (k (pop v))) + (pcase k + ((or "user" "username") + (unless (or user u) + (setq u v + cached (plist-put cached :user u)))) + ("port" + (unless (or port p) + (setq p (auth-source-pass--cast-port v port) + cached (plist-put cached :port p)))) + ((pred stringp) + (push (intern (concat ":" k)) extras) + (push v extras) + (push (cons k v) tmp)))) + (setq attrs (nreverse tmp))) (puthash entry (plist-put cached :attrs attrs) seen) `( :host ,host ,@(and u (list :user u)) ,@(and p (list :port p)) - ,@(and s (not (eq s t)) (list :secret s))))))) + ,@(and s (not (eq s t)) (list :secret s)) + ,@(nreverse extras)))))) (defun auth-source-pass--find-match-many (hosts users ports require max) "Return plists for valid combinations of HOSTS, USERS, PORTS." diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 2ce5d12a6bc..c6662cd8b42 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -668,6 +668,23 @@ auth-source-pass-extra-query-keywords--akib/attr/require (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/extras () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") + ("port" . "42") + ("foo" . "1") + ("bar" . "2")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :port "42" + :secret "b" :foo "1" :bar "2"))))))) + ;; Searches for :host are case-sensitive, and a returned host isn't ;; normalized. -- 2.46.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0001-POC-Match-attrs-with-auth-source-pass-extra-query-ke.patch --] [-- Type: text/x-patch, Size: 15077 bytes --] From a0381a48cb4ff960ef2dd55dd511f5c18e535f6e Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Wed, 7 Aug 2024 22:23:09 -0700 Subject: [PATCH 1/1] [POC] Match attrs with auth-source-pass-extra-query-keywords * lisp/auth-source-pass.el (auth-source-pass--retrieve-parsed): Remove unused function. (auth-source-pass--cast-port): New function, a helper to match an entry's port to the given query param's type. (auth-source-pass--match-parts): Return non-nil when a key is required but the value is null. Not doing produced behavior that deviated from the reference netrc implementation and was thus a bug. (auth-source-pass-check-attrs-with-extra-query-keywords): New variable, a flag to opt out of arguably expensive attribute lookups. (auth-source-pass--find-matched-entry): New function to isolate processing logic for a single entry. (auth-source-pass--find-match-many): Move single-entry processing logic to separate helper, mainly for readability. * test/lisp/auth-source-pass-tests.el (auth-source-pass-extra-query-keywords--akib/attr) (auth-source-pass-extra-query-keywords--netrc-akib/require) (auth-source-pass-extra-query-keywords--akib/attr/require) (auth-source-pass-extra-query-keywords--akib/attr/extras) (auth-source-pass-extra-query-keywords--netrc-baseline): New tests. (auth-source-pass-extra-query-keywords--baseline): Reverse expected outcome to match reference implementation. That it didn't before was a bug. (Bug#72441) --- lisp/auth-source-pass.el | 143 ++++++++++++++++++++-------- test/lisp/auth-source-pass-tests.el | 96 ++++++++++++++++++- 2 files changed, 195 insertions(+), 44 deletions(-) diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 03fd1f35811..0df7817f501 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -256,32 +256,101 @@ auth-source-pass--find-match hosts (list hosts)))) -(defun auth-source-pass--retrieve-parsed (seen path port-number-p) - (when (string-match auth-source-pass--match-regexp path) - (puthash path - `( :host ,(or (match-string 10 path) (match-string 11 path)) - ,@(if-let* ((tr (match-string 21 path))) - (list :user tr :suffix t) - (list :user (match-string 20 path))) - :port ,(and-let* ((p (or (match-string 30 path) - (match-string 31 path))) - (n (string-to-number p))) - (if (or (zerop n) (not port-number-p)) - (format "%s" p) - n))) - seen))) - -(defun auth-source-pass--match-parts (parts key value require) - (let ((mv (plist-get parts key))) +(defun auth-source-pass--cast-port (val ref) + (cond ((integerp val) val) + ((and-let* (((integerp ref)) + (n (string-to-number val)) + ((not (zerop n)))) + n)) + (t (format "%s" val)))) + +(defun auth-source-pass--match-parts (cache key reference require) + (let ((value (plist-get cache key))) (if (memq key require) - (and value (equal mv value)) - (or (not value) (not mv) (equal mv value))))) + (if reference (equal value reference) value) + (or (null reference) (null value) (equal value reference))))) + +(defvar auth-source-pass-check-attrs-with-extra-query-keywords t + "When non-nil, decrypt files to find attributes matching parameters. +However, give precedence to fields encoded in file names. Only applies +when `auth-source-pass-extra-query-keywords' is non-nil.") + +;; This function tries to defer decryption as long as possible. For +;; that reason, an entry's file-path-derived :port or :user field +;; always takes precedence over their counterparts from a decrypted +;; file's attribute list. +(defun auth-source-pass--find-matched-entry (host user port require seen entry) + "Match ENTRY against query params HOST USER PORT REQUIRE with cache SEEN." + (when (string-match auth-source-pass--match-regexp entry) + (let* ((cached (gethash entry seen)) + (optp auth-source-pass-check-attrs-with-extra-query-keywords) + (suffixedp nil) + (h (or (and cached (plist-get cached :host)) + (match-string 10 entry) + (match-string 11 entry))) + (attrs (and cached (plist-get :attrs cached))) + (getat (lambda (k) + (save-match-data + (unless attrs + (setq attrs (auth-source-pass-parse-entry entry))) + (auth-source-pass--get-attr k attrs)))) + (u (cond (cached (plist-get cached :user)) + ((and-let* ((u (match-string 21 entry))) + (setq suffixedp t) + u)) + ((match-string 20 entry)) + ((and optp (or user (memq :user require))) + (funcall getat "user")))) + (p (cond (cached (plist-get cached :port)) + ((match-string 30 entry)) + ((match-string 31 entry)) + ((and optp (or port (memq :port require))) + (funcall getat "port")))) + ;; + s extras) + (when p + (setq p (auth-source-pass--cast-port p port))) + (unless cached + (setq cached `( :host ,h + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and suffixedp (list :suffix t)) + ,@(and attrs (list :attrs attrs)))) + (puthash entry cached seen)) + (when (and (equal host h) + (auth-source-pass--match-parts cached :port port require) + (auth-source-pass--match-parts cached :user user require) + (setq s (or (funcall getat 'secret) + (not (memq :secret require))))) + (let (tmp) + (while-let ((v (pop attrs)) + (k (pop v))) + (pcase k + ((or "user" "username") + (unless (or user u) + (setq u v + cached (plist-put cached :user u)))) + ("port" + (unless (or port p) + (setq p (auth-source-pass--cast-port v port) + cached (plist-put cached :port p)))) + ((pred stringp) + (push (intern (concat ":" k)) extras) + (push v extras) + (push (cons k v) tmp)))) + (setq attrs (nreverse tmp))) + (puthash entry (plist-put cached :attrs attrs) seen) + `( :host ,host + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and s (not (eq s t)) (list :secret s)) + ,@(nreverse extras)))))) (defun auth-source-pass--find-match-many (hosts users ports require max) "Return plists for valid combinations of HOSTS, USERS, PORTS." (let ((seen (make-hash-table :test #'equal)) (entries (auth-source-pass-entries)) - out suffixed suffixedp) + out suffixed) (catch 'done (dolist (host hosts out) (pcase-let ((`(,_ ,u ,p) (auth-source-pass--disambiguate host))) @@ -289,28 +358,18 @@ auth-source-pass--find-match-many (setq p nil)) (dolist (user (or users (list u))) (dolist (port (or ports (list p))) - (dolist (e entries) - (when-let* - ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed - seen e (integerp port)))) - ((equal host (plist-get m :host))) - ((auth-source-pass--match-parts m :port port require)) - ((auth-source-pass--match-parts m :user user require)) - (parsed (auth-source-pass-parse-entry e)) - ;; For now, ignore body-content pairs, if any, - ;; from `auth-source-pass--parse-data'. - (secret (or (auth-source-pass--get-attr 'secret parsed) - (not (memq :secret require))))) - (push - `( :host ,host ; prefer user-provided :host over h - ,@(and-let* ((u (plist-get m :user))) (list :user u)) - ,@(and-let* ((p (plist-get m :port))) (list :port p)) - ,@(and secret (not (eq secret t)) (list :secret secret))) - (if (setq suffixedp (plist-get m :suffix)) suffixed out)) - (unless suffixedp - (when (or (zerop (cl-decf max)) - (null (setq entries (delete e entries)))) - (throw 'done out))))) + (dolist (entry entries) + (let* ((result (auth-source-pass--find-matched-entry + host user port require seen entry)) + ;; + suffixedp) + (when result + (setq suffixedp (plist-get (gethash entry seen) :suffix)) + (push result (if suffixedp suffixed out)) + (unless suffixedp + (when (or (zerop (cl-decf max)) + (null (setq entries (delete entry entries)))) + (throw 'done out)))))) (setq suffixed (nreverse suffixed)) (while suffixed (push (pop suffixed) out) diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 6455c3393d5..c6662cd8b42 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -601,6 +601,90 @@ auth-source-pass-extra-query-keywords--akib (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") ("port" . "42")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + results) + + ;; Non-matching query param. + (setq results (auth-source-search :host "disroot.org" :user "?" :max 2)) + (should-not results) + + ;; No query params matching attrs. + (setq results (auth-source-search :host "disroot.org" :max 2)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching user query param. + (setq results (auth-source-search :host "disroot.org" :user "akib")) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching port typed query param. + (setq results (auth-source-search :host "disroot.org" :port 42)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port 42 :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--netrc-akib/require () + (ert-with-temp-file netrc-file + :text "\ +machine x.com password a +machine disroot.org user akib password b +machine z.com password c +" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "disroot.org" + :require '(:user) :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/require () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" + :require '(:user) :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/extras () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") + ("port" . "42") + ("foo" . "1") + ("bar" . "2")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :port "42" + :secret "b" :foo "1" :bar "2"))))))) + ;; Searches for :host are case-sensitive, and a returned host isn't ;; normalized. @@ -632,11 +716,19 @@ auth-source-pass-extra-query-keywords--host ;; A retrieved store entry mustn't be nil regardless of whether its ;; path contains port or user components. +(ert-deftest auth-source-pass-extra-query-keywords--netrc-baseline () + (ert-with-temp-file netrc-file + :text "machine foo\n" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "foo"))) + (should (equal results '((:host "foo"))))))) + (ert-deftest auth-source-pass-extra-query-keywords--baseline () (let ((auth-source-pass-extra-query-keywords t)) - (auth-source-pass--with-store '(("x.com")) + (auth-source-pass--with-store '(("foo")) (auth-source-pass-enable) - (should-not (auth-source-search :host "x.com"))))) + (should (equal (auth-source-search :host "foo") '((:host "foo"))))))) ;; Output port type (int or string) matches that of input parameter. -- 2.46.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true 2024-08-10 13:58 ` J.P. @ 2024-08-12 19:33 ` J.P. 2024-09-06 23:16 ` J.P. 0 siblings, 1 reply; 6+ messages in thread From: J.P. @ 2024-08-12 19:33 UTC (permalink / raw) To: 72441; +Cc: Björn Bidar [-- Attachment #1: Type: text/plain, Size: 481 bytes --] While exploring ways to tackle this feature, I stumbled on a couple minor bugs related to `auth-source-pass-extra-query-keywords'. Because there's no telling when we'll end up with something installable for this feature, I've gone ahead and isolated the fixes into a separate patch (0001 in the attached). It's probably safe enough for Emacs 30, but since the option was introduced back in 29, I'll just install it on master (unless I hear otherwise in the coming days). Thanks. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0000-v2-v3.diff --] [-- Type: text/x-patch, Size: 7149 bytes --] From d9bd10debf6c3930669aedb896026f9f19b54466 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Mon, 12 Aug 2024 07:00:23 -0700 Subject: [PATCH 0/2] *** NOT A PATCH *** *** BLURB HERE *** F. Jason Park (2): Fix deviations in auth-source-pass behavior WRT netrc [POC] Match attrs with auth-source-pass-extra-query-keywords lisp/auth-source-pass.el | 146 ++++++++++++++++++++-------- test/lisp/auth-source-pass-tests.el | 138 +++++++++++++++++++++++++- 2 files changed, 237 insertions(+), 47 deletions(-) Interdiff: diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 0df7817f501..a52dafc5ab2 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -266,9 +266,10 @@ auth-source-pass--cast-port (defun auth-source-pass--match-parts (cache key reference require) (let ((value (plist-get cache key))) - (if (memq key require) - (if reference (equal value reference) value) - (or (null reference) (null value) (equal value reference))))) + (cond ((memq key require) + (if reference (equal value reference) value)) + ((and value reference) (equal value reference)) + (t)))) (defvar auth-source-pass-check-attrs-with-extra-query-keywords t "When non-nil, decrypt files to find attributes matching parameters. diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index c6662cd8b42..695635299f9 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -548,6 +548,44 @@ auth-source-pass-extra-query-keywords--wild-port-hit '((:host "x.com" :secret "a") (:host "x.com" :port 42 :secret "b"))))))) +;; The query requires a user and doesn't specify a user to match against. +;; The only entry matching the host lacks a user, so the search fails. + +(ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss-netrc () + (ert-with-temp-file netrc-file + :text "machine foo password a\n" + (let ((auth-sources (list netrc-file)) + (auth-source-do-cache nil)) + (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) + +(ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss () + (let ((auth-source-pass-extra-query-keywords t)) + (auth-source-pass--with-store '(("foo" (secret . "a"))) + (auth-source-pass-enable) + (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) + +;; The query requires a user but does not provide a reference value to +;; match against. An entry matching the host that specifies a user is +;; selected because any user will do. +(ert-deftest auth-source-pass-extra-query-keywords--req-param-netrc () + (ert-with-temp-file netrc-file + :text "machine foo login bob password a\n" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "foo" :require '(:user)))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results '((:host "foo" :user "bob" :secret "a"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--req-param () + (let ((auth-source-pass-extra-query-keywords t)) + (auth-source-pass--with-store '(("foo/bob" (secret . "a"))) + (auth-source-pass-enable) + (let ((results (auth-source-search :host "foo" :require '(:user)))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results '((:host "foo" :user "bob" :secret "a")))))))) + ;; No entry has the requested port, but :port is required, so search fails. (ert-deftest auth-source-pass-extra-query-keywords--wild-port-req-miss-netrc () @@ -601,7 +639,7 @@ auth-source-pass-extra-query-keywords--akib (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) -(ert-deftest auth-source-pass-extra-query-keywords--akib/attr () +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr () (auth-source-pass--with-store '(("x.com" (secret . "a")) ("disroot.org" (secret . "b") ("user" . "akib") ("port" . "42")) @@ -638,23 +676,7 @@ auth-source-pass-extra-query-keywords--akib/attr '(( :host "disroot.org" :user "akib" :port 42 :secret "b"))))))) -(ert-deftest auth-source-pass-extra-query-keywords--netrc-akib/require () - (ert-with-temp-file netrc-file - :text "\ -machine x.com password a -machine disroot.org user akib password b -machine z.com password c -" - (let* ((auth-sources (list netrc-file)) - (auth-source-do-cache nil) - (results (auth-source-search :host "disroot.org" - :require '(:user) :max 2))) - (dolist (result results) - (setf (plist-get result :secret) (auth-info-password result))) - (should (equal results - '((:host "disroot.org" :user "akib" :secret "b"))))))) - -(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/require () +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-req () (auth-source-pass--with-store '(("x.com" (secret . "a")) ("disroot.org" (secret . "b") ("user" . "akib")) @@ -668,7 +690,23 @@ auth-source-pass-extra-query-keywords--akib/attr/require (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) -(ert-deftest auth-source-pass-extra-query-keywords--akib/attr/extras () +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-extras-netrc () + (ert-with-temp-file netrc-file + :text "\ +machine x.com password a +machine disroot.org user akib port 42 password b foo 1 bar 2 +machine z.com password c +" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "disroot.org" :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :port "42" + :secret "b" :foo "1" :bar "2"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-extras () (auth-source-pass--with-store '(("x.com" (secret . "a")) ("disroot.org" (secret . "b") ("user" . "akib") @@ -713,8 +751,8 @@ auth-source-pass-extra-query-keywords--host '((:host "Libera.Chat" :secret "b"))))))) -;; A retrieved store entry mustn't be nil regardless of whether its -;; path contains port or user components. +;; An effectively empty entry in the store returns nothing but the +;; :host field matching the given host parameter. (ert-deftest auth-source-pass-extra-query-keywords--netrc-baseline () (ert-with-temp-file netrc-file -- 2.46.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0001-Fix-deviations-in-auth-source-pass-behavior-WRT-netr.patch --] [-- Type: text/x-patch, Size: 7898 bytes --] From 1aa0f941d79b77de4a87a8043f13607c0719f5d0 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Sun, 11 Aug 2024 21:55:32 -0700 Subject: [PATCH 1/2] Fix deviations in auth-source-pass behavior WRT netrc The option `auth-source-pass-extra-query-keywords' aims to make this back end hew as close to the other built-in ones as possible, except WRT features not yet implemented, such as arbitrary "attribute" retrieval and new entry creation. This change only concerns behavior exhibited when the option is enabled. * lisp/auth-source-pass.el (auth-source-pass--match-parts): Account for the case in which a query lacks a reference parameter for a `:port' or `:user' but still requires one or both via the `:require' keyword. Previously, such a query would fail even when an entry met this requirement by simply specifying a field with any non-null value corresponding to the required parameter. (auth-source-pass--find-match-many): Account for the baseline case where a matching entry lacks a secret and the user doesn't require one. Although this function doesn't currently return so-called "attributes" from the contents of a matching decrypted file, were it to eventually, this case would no longer be academic. * test/lisp/auth-source-pass-tests.el (auth-source-pass-extra-query-keywords--req-noparam-miss-netrc) (auth-source-pass-extra-query-keywords--req-noparam-miss) (auth-source-pass-extra-query-keywords--req-param-netrc) (auth-source-pass-extra-query-keywords--req-param): New tests. (auth-source-pass-extra-query-keywords--netrc-baseline): New test asserting behavior of netrc backend when passed a lone `:host' as a query parameter. (auth-source-pass-extra-query-keywords--baseline): Reverse expected outcome to match that of the netrc reference implementation. (bug#72441) --- lisp/auth-source-pass.el | 19 +++++----- test/lisp/auth-source-pass-tests.el | 54 ++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index 03fd1f35811..dd93d414d5e 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -271,11 +271,12 @@ auth-source-pass--retrieve-parsed n))) seen))) -(defun auth-source-pass--match-parts (parts key value require) - (let ((mv (plist-get parts key))) - (if (memq key require) - (and value (equal mv value)) - (or (not value) (not mv) (equal mv value))))) +(defun auth-source-pass--match-parts (cache key reference require) + (let ((value (plist-get cache key))) + (cond ((memq key require) + (if reference (equal value reference) value)) + ((and value reference) (equal value reference)) + (t)))) (defun auth-source-pass--find-match-many (hosts users ports require max) "Return plists for valid combinations of HOSTS, USERS, PORTS." @@ -290,17 +291,17 @@ auth-source-pass--find-match-many (dolist (user (or users (list u))) (dolist (port (or ports (list p))) (dolist (e entries) - (when-let* + (when-let ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed seen e (integerp port)))) ((equal host (plist-get m :host))) ((auth-source-pass--match-parts m :port port require)) ((auth-source-pass--match-parts m :user user require)) - (parsed (auth-source-pass-parse-entry e)) ;; For now, ignore body-content pairs, if any, ;; from `auth-source-pass--parse-data'. - (secret (or (auth-source-pass--get-attr 'secret parsed) - (not (memq :secret require))))) + (secret (let ((parsed (auth-source-pass-parse-entry e))) + (or (auth-source-pass--get-attr 'secret parsed) + (not (memq :secret require)))))) (push `( :host ,host ; prefer user-provided :host over h ,@(and-let* ((u (plist-get m :user))) (list :user u)) diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index 6455c3393d5..c54936c3f92 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -548,6 +548,44 @@ auth-source-pass-extra-query-keywords--wild-port-hit '((:host "x.com" :secret "a") (:host "x.com" :port 42 :secret "b"))))))) +;; The query requires a user and doesn't specify a user to match against. +;; The only entry matching the host lacks a user, so the search fails. + +(ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss-netrc () + (ert-with-temp-file netrc-file + :text "machine foo password a\n" + (let ((auth-sources (list netrc-file)) + (auth-source-do-cache nil)) + (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) + +(ert-deftest auth-source-pass-extra-query-keywords--req-noparam-miss () + (let ((auth-source-pass-extra-query-keywords t)) + (auth-source-pass--with-store '(("foo" (secret . "a"))) + (auth-source-pass-enable) + (should-not (auth-source-search :host "foo" :require '(:user) :max 2))))) + +;; The query requires a user but does not provide a reference value to +;; match against. An entry matching the host that specifies a user is +;; selected because any user will do. +(ert-deftest auth-source-pass-extra-query-keywords--req-param-netrc () + (ert-with-temp-file netrc-file + :text "machine foo login bob password a\n" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "foo" :require '(:user)))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results '((:host "foo" :user "bob" :secret "a"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--req-param () + (let ((auth-source-pass-extra-query-keywords t)) + (auth-source-pass--with-store '(("foo/bob" (secret . "a"))) + (auth-source-pass-enable) + (let ((results (auth-source-search :host "foo" :require '(:user)))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results '((:host "foo" :user "bob" :secret "a")))))))) + ;; No entry has the requested port, but :port is required, so search fails. (ert-deftest auth-source-pass-extra-query-keywords--wild-port-req-miss-netrc () @@ -629,14 +667,22 @@ auth-source-pass-extra-query-keywords--host '((:host "Libera.Chat" :secret "b"))))))) -;; A retrieved store entry mustn't be nil regardless of whether its -;; path contains port or user components. +;; An effectively empty entry in the store returns nothing but the +;; :host field matching the given host parameter. + +(ert-deftest auth-source-pass-extra-query-keywords--netrc-baseline () + (ert-with-temp-file netrc-file + :text "machine foo\n" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "foo"))) + (should (equal results '((:host "foo"))))))) (ert-deftest auth-source-pass-extra-query-keywords--baseline () (let ((auth-source-pass-extra-query-keywords t)) - (auth-source-pass--with-store '(("x.com")) + (auth-source-pass--with-store '(("foo")) (auth-source-pass-enable) - (should-not (auth-source-search :host "x.com"))))) + (should (equal (auth-source-search :host "foo") '((:host "foo"))))))) ;; Output port type (int or string) matches that of input parameter. -- 2.46.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0002-POC-Match-attrs-with-auth-source-pass-extra-query-ke.patch --] [-- Type: text/x-patch, Size: 13936 bytes --] From d9bd10debf6c3930669aedb896026f9f19b54466 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" <jp@neverwas.me> Date: Wed, 7 Aug 2024 22:23:09 -0700 Subject: [PATCH 2/2] [POC] Match attrs with auth-source-pass-extra-query-keywords * lisp/auth-source-pass.el (auth-source-pass--retrieve-parsed): Remove unused function. (auth-source-pass--cast-port): New function, a helper to match an entry's port to the given query param's type. (auth-source-pass--match-parts): Return non-nil when a key is required but the value is null. Not doing so produced behavior that deviated from the reference netrc implementation and was thus a bug. (auth-source-pass-check-attrs-with-extra-query-keywords): New variable, a flag to opt out of arguably expensive attribute lookups. (auth-source-pass--find-matched-entry): New function to isolate processing logic for a single entry. (auth-source-pass--find-match-many): Move single-entry processing logic to separate helper, mainly for readability. * test/lisp/auth-source-pass-tests.el (auth-source-pass-extra-query-keywords--akib-attr) (auth-source-pass-extra-query-keywords--akib-attr-req) (auth-source-pass-extra-query-keywords--akib-attr-netrc) (auth-source-pass-extra-query-keywords--akib-attr-extras) (auth-source-pass-extra-query-keywords--netrc-baseline): New tests. (auth-source-pass-extra-query-keywords--baseline): Reverse expected outcome to match reference implementation. That it didn't before was a bug. (Bug#72441) --- lisp/auth-source-pass.el | 133 ++++++++++++++++++++-------- test/lisp/auth-source-pass-tests.el | 84 ++++++++++++++++++ 2 files changed, 180 insertions(+), 37 deletions(-) diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el index dd93d414d5e..a52dafc5ab2 100644 --- a/lisp/auth-source-pass.el +++ b/lisp/auth-source-pass.el @@ -256,20 +256,13 @@ auth-source-pass--find-match hosts (list hosts)))) -(defun auth-source-pass--retrieve-parsed (seen path port-number-p) - (when (string-match auth-source-pass--match-regexp path) - (puthash path - `( :host ,(or (match-string 10 path) (match-string 11 path)) - ,@(if-let* ((tr (match-string 21 path))) - (list :user tr :suffix t) - (list :user (match-string 20 path))) - :port ,(and-let* ((p (or (match-string 30 path) - (match-string 31 path))) - (n (string-to-number p))) - (if (or (zerop n) (not port-number-p)) - (format "%s" p) - n))) - seen))) +(defun auth-source-pass--cast-port (val ref) + (cond ((integerp val) val) + ((and-let* (((integerp ref)) + (n (string-to-number val)) + ((not (zerop n)))) + n)) + (t (format "%s" val)))) (defun auth-source-pass--match-parts (cache key reference require) (let ((value (plist-get cache key))) @@ -278,11 +271,87 @@ auth-source-pass--match-parts ((and value reference) (equal value reference)) (t)))) +(defvar auth-source-pass-check-attrs-with-extra-query-keywords t + "When non-nil, decrypt files to find attributes matching parameters. +However, give precedence to fields encoded in file names. Only applies +when `auth-source-pass-extra-query-keywords' is non-nil.") + +;; This function tries to defer decryption as long as possible. For +;; that reason, an entry's file-path-derived :port or :user field +;; always takes precedence over their counterparts from a decrypted +;; file's attribute list. +(defun auth-source-pass--find-matched-entry (host user port require seen entry) + "Match ENTRY against query params HOST USER PORT REQUIRE with cache SEEN." + (when (string-match auth-source-pass--match-regexp entry) + (let* ((cached (gethash entry seen)) + (optp auth-source-pass-check-attrs-with-extra-query-keywords) + (suffixedp nil) + (h (or (and cached (plist-get cached :host)) + (match-string 10 entry) + (match-string 11 entry))) + (attrs (and cached (plist-get :attrs cached))) + (getat (lambda (k) + (save-match-data + (unless attrs + (setq attrs (auth-source-pass-parse-entry entry))) + (auth-source-pass--get-attr k attrs)))) + (u (cond (cached (plist-get cached :user)) + ((and-let* ((u (match-string 21 entry))) + (setq suffixedp t) + u)) + ((match-string 20 entry)) + ((and optp (or user (memq :user require))) + (funcall getat "user")))) + (p (cond (cached (plist-get cached :port)) + ((match-string 30 entry)) + ((match-string 31 entry)) + ((and optp (or port (memq :port require))) + (funcall getat "port")))) + ;; + s extras) + (when p + (setq p (auth-source-pass--cast-port p port))) + (unless cached + (setq cached `( :host ,h + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and suffixedp (list :suffix t)) + ,@(and attrs (list :attrs attrs)))) + (puthash entry cached seen)) + (when (and (equal host h) + (auth-source-pass--match-parts cached :port port require) + (auth-source-pass--match-parts cached :user user require) + (setq s (or (funcall getat 'secret) + (not (memq :secret require))))) + (let (tmp) + (while-let ((v (pop attrs)) + (k (pop v))) + (pcase k + ((or "user" "username") + (unless (or user u) + (setq u v + cached (plist-put cached :user u)))) + ("port" + (unless (or port p) + (setq p (auth-source-pass--cast-port v port) + cached (plist-put cached :port p)))) + ((pred stringp) + (push (intern (concat ":" k)) extras) + (push v extras) + (push (cons k v) tmp)))) + (setq attrs (nreverse tmp))) + (puthash entry (plist-put cached :attrs attrs) seen) + `( :host ,host + ,@(and u (list :user u)) + ,@(and p (list :port p)) + ,@(and s (not (eq s t)) (list :secret s)) + ,@(nreverse extras)))))) + (defun auth-source-pass--find-match-many (hosts users ports require max) "Return plists for valid combinations of HOSTS, USERS, PORTS." (let ((seen (make-hash-table :test #'equal)) (entries (auth-source-pass-entries)) - out suffixed suffixedp) + out suffixed) (catch 'done (dolist (host hosts out) (pcase-let ((`(,_ ,u ,p) (auth-source-pass--disambiguate host))) @@ -290,28 +359,18 @@ auth-source-pass--find-match-many (setq p nil)) (dolist (user (or users (list u))) (dolist (port (or ports (list p))) - (dolist (e entries) - (when-let - ((m (or (gethash e seen) (auth-source-pass--retrieve-parsed - seen e (integerp port)))) - ((equal host (plist-get m :host))) - ((auth-source-pass--match-parts m :port port require)) - ((auth-source-pass--match-parts m :user user require)) - ;; For now, ignore body-content pairs, if any, - ;; from `auth-source-pass--parse-data'. - (secret (let ((parsed (auth-source-pass-parse-entry e))) - (or (auth-source-pass--get-attr 'secret parsed) - (not (memq :secret require)))))) - (push - `( :host ,host ; prefer user-provided :host over h - ,@(and-let* ((u (plist-get m :user))) (list :user u)) - ,@(and-let* ((p (plist-get m :port))) (list :port p)) - ,@(and secret (not (eq secret t)) (list :secret secret))) - (if (setq suffixedp (plist-get m :suffix)) suffixed out)) - (unless suffixedp - (when (or (zerop (cl-decf max)) - (null (setq entries (delete e entries)))) - (throw 'done out))))) + (dolist (entry entries) + (let* ((result (auth-source-pass--find-matched-entry + host user port require seen entry)) + ;; + suffixedp) + (when result + (setq suffixedp (plist-get (gethash entry seen) :suffix)) + (push result (if suffixedp suffixed out)) + (unless suffixedp + (when (or (zerop (cl-decf max)) + (null (setq entries (delete entry entries)))) + (throw 'done out)))))) (setq suffixed (nreverse suffixed)) (while suffixed (push (pop suffixed) out) diff --git a/test/lisp/auth-source-pass-tests.el b/test/lisp/auth-source-pass-tests.el index c54936c3f92..695635299f9 100644 --- a/test/lisp/auth-source-pass-tests.el +++ b/test/lisp/auth-source-pass-tests.el @@ -639,6 +639,90 @@ auth-source-pass-extra-query-keywords--akib (should (equal results '((:host "disroot.org" :user "akib" :secret "b"))))))) +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") ("port" . "42")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + results) + + ;; Non-matching query param. + (setq results (auth-source-search :host "disroot.org" :user "?" :max 2)) + (should-not results) + + ;; No query params matching attrs. + (setq results (auth-source-search :host "disroot.org" :max 2)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching user query param. + (setq results (auth-source-search :host "disroot.org" :user "akib")) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port "42" :secret "b")))) + + ;; Matching port typed query param. + (setq results (auth-source-search :host "disroot.org" :port 42)) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '(( :host "disroot.org" :user "akib" + :port 42 :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-req () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" + :require '(:user) :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :secret "b"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-extras-netrc () + (ert-with-temp-file netrc-file + :text "\ +machine x.com password a +machine disroot.org user akib port 42 password b foo 1 bar 2 +machine z.com password c +" + (let* ((auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (results (auth-source-search :host "disroot.org" :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :port "42" + :secret "b" :foo "1" :bar "2"))))))) + +(ert-deftest auth-source-pass-extra-query-keywords--akib-attr-extras () + (auth-source-pass--with-store '(("x.com" (secret . "a")) + ("disroot.org" (secret . "b") + ("user" . "akib") + ("port" . "42") + ("foo" . "1") + ("bar" . "2")) + ("z.com" (secret . "c"))) + (auth-source-pass-enable) + (let* ((auth-source-pass-extra-query-keywords t) + (results (auth-source-search :host "disroot.org" :max 2))) + (dolist (result results) + (setf (plist-get result :secret) (auth-info-password result))) + (should (equal results + '((:host "disroot.org" :user "akib" :port "42" + :secret "b" :foo "1" :bar "2"))))))) + ;; Searches for :host are case-sensitive, and a returned host isn't ;; normalized. -- 2.46.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true 2024-08-12 19:33 ` J.P. @ 2024-09-06 23:16 ` J.P. 0 siblings, 0 replies; 6+ messages in thread From: J.P. @ 2024-09-06 23:16 UTC (permalink / raw) To: 72441; +Cc: Björn Bidar "J.P." <jp@neverwas.me> writes: > While exploring ways to tackle this feature, I stumbled on a couple > minor bugs related to `auth-source-pass-extra-query-keywords'. > > Because there's no telling when we'll end up with something installable > for this feature, I've gone ahead and isolated the fixes into a separate > patch (0001 in the attached). It's probably safe enough for Emacs 30, > but since the option was introduced back in 29, I'll just install it on > master (unless I hear otherwise in the coming days). Thanks. Installed on master as https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=80228d1f As previously mentioned, the above commit only addresses an ancillary issue, so the bug should remain open. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-09-06 23:16 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-08-03 11:12 bug#72441: 31.0.50; Auth-source-pass doesn't match password attributes or hosts without user when extra-query-keywords is true Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-08-09 18:02 ` J.P. 2024-08-09 19:20 ` Björn Bidar via Bug reports for GNU Emacs, the Swiss army knife of text editors [not found] ` <87ed6xy03r.fsf@> 2024-08-10 13:58 ` J.P. 2024-08-12 19:33 ` J.P. 2024-09-06 23:16 ` J.P.
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).