From 4a7c98d21c20d3c9740789ba53054556486d7e04 Mon Sep 17 00:00:00 2001 From: Ted Zlatanov Date: Thu, 18 Jun 2020 14:32:51 -0400 Subject: [PATCH] Create and document auth-source-reveal-mode * lisp/auth-source.el (auth-source-reveal-mode): Add new minor mode to hide passwords. Remove authinfo-mode which provided a major mode for the same purpose before. * doc/misc/auth.texi (Hiding passwords in text buffers): Document auth-source-reveal-mode. --- doc/misc/auth.texi | 47 +++++++++++++++++++- lisp/auth-source.el | 106 +++++++++++++++++++++++++++++++------------- 2 files changed, 121 insertions(+), 32 deletions(-) diff --git a/doc/misc/auth.texi b/doc/misc/auth.texi index 61dc62e7711..e51bcfe092d 100644 --- a/doc/misc/auth.texi +++ b/doc/misc/auth.texi @@ -1,6 +1,6 @@ \input texinfo @c -*-texinfo-*- -@set VERSION 0.3 +@set VERSION 0.4 @setfilename ../../info/auth.info @settitle Emacs auth-source Library @value{VERSION} @@ -58,6 +58,7 @@ It is a way for multiple applications to share a single configuration * Overview:: Overview of the auth-source library. * Help for users:: * Multiple GMail accounts with Gnus:: +* Hiding passwords in text buffers:: * Secret Service API:: * The Unix password store:: * Help for developers:: @@ -280,6 +281,50 @@ machine gmail login account@@gmail.com password "account password" port imap machine gmail2 login account2@@gmail.com password "account2 password" port imap @end example +@node Hiding passwords in text buffers +@chapter Hiding passwords in text buffers + +Emacs users and developers have to look at netrc files in text or JSON +formats sometimes. Pro Tip: one easy way to protect from +password-shoulder-surfers is to enter a hair band, grow long hair, +curl it daily until it creates a visual barrier, become famous, keep +using Emacs. + +An alternative is to enable @code{auth-source-reveal-mode} as follows: + +@example +(require 'auth-source) +(setq prettify-symbols-unprettify-at-point 'right-edge) ;; or customize it + +(add-hook 'prog-mode-hook 'turn-on-auth-source-reveal-mode) +(add-hook 'text-mode-hook 'turn-on-auth-source-reveal-mode) +(add-hook 'json-mode-hook 'turn-on-auth-source-reveal-mode) +@end example + +You should definitely customize +@code{prettify-symbols-unprettify-at-point} to be t or +@code{right-edge}. If it's nil (the default), the password will not be +revealed when you're inside it, which will annoy you AND +password-shoulder-surfers. + +You can further customize the following. +@defvar auth-source-reveal-regex +A regular expression matching the text preceding the password (or, in JSON format, the key under which the password lives). By default it will be just ``password'' which also matches e.g. ``my_password''. + +Use only non-capturing parens inside this regular expression. +@end defvar + +@defvar auth-source-reveal-json-modes +This is a list of modes where the JSON regular expression logic should be installed, instead of the plaintext logic. By default this includes @code{json-mode} for instance. +@end defvar + +@itemize @bullet +@item +Q: How does it work? A: Underneath, @code{prettify-symbols-mode} is used to hide passwords based on a regular expression for netrc plain text or JSON files. +@item +Q: Why does it depend on prettify-symbols-mode? A: Eventually it won't. For now it does. +@end itemize + @node Secret Service API @chapter Secret Service API diff --git a/lisp/auth-source.el b/lisp/auth-source.el index 7a0e09b9e8e..76e9c875725 100644 --- a/lisp/auth-source.el +++ b/lisp/auth-source.el @@ -44,6 +44,7 @@ (require 'cl-lib) (require 'eieio) +(require 'prog-mode) (autoload 'secrets-create-item "secrets") (autoload 'secrets-delete-item "secrets") @@ -2405,44 +2406,87 @@ MODE can be \"login\" or \"password\"." (setq password (funcall password))) (list user password auth-info))) -;;; Tiny mode for editing .netrc/.authinfo modes (that basically just -;;; hides passwords). +;;; Tiny minor mode for editing .netrc/.authinfo modes (that basically +;;; just hides passwords). -(defcustom authinfo-hidden "password" - "Regexp matching elements in .authinfo/.netrc files that should be hidden." +(defcustom auth-source-reveal-regex "password" + "Regexp matching tokens or JSON keys in .authinfo/.netrc/JSON files. +The text following the tokens or under the JSON keys will be hidden." :type 'regexp :version "27.1") -;;;###autoload -(define-derived-mode authinfo-mode fundamental-mode "Authinfo" - "Mode for editing .authinfo/.netrc files. +(defcustom auth-source-reveal-json-modes '(json-mode js-mode js2-mode rjsx-mode) + "List of symbols for modes that should use JSON parsing logic." + :type 'list + :version "27.1") -This is just like `fundamental-mode', but hides passwords. The -passwords are revealed when point moved into the password. +(defcustom auth-source-reveal-hider '(?* (base-right . base-left) ?© (base-right . base-left) ?© (base-right . base-left) ?*) + "A character or a composition list to hide passwords. +In the composition list form, you can use the format +(?h (base-right . base-left) ?i (base-right . base-left) ?d (base-right . base-left) ?e) +to show the string \"hide\" (by aligning character left/right baselines). -\\{authinfo-mode-map}" - (authinfo--hide-passwords (point-min) (point-max)) - (reveal-mode)) +Other composition keywords you can use: top-left/tl, +top-center/tc, top-right/tr, base-left/Bl, base-center/Bc, +base-right/Br, bottom-left/bl, bottom-center/bc, bottom-right/br, +center-left/cl, center-center/cc, center-right/cr." + :type '(choice + (const :tag "A single copyright sign" ?©) + (character :tag "Any character") + (sexp :tag "A composition list")) + :version "27.1") -(defun authinfo--hide-passwords (start end) - (save-excursion - (save-restriction - (narrow-to-region start end) - (goto-char start) - (while (re-search-forward (format "\\(\\s-\\|^\\)\\(%s\\)\\s-+" - authinfo-hidden) - nil t) - (when (auth-source-netrc-looking-at-token) - (let ((overlay (make-overlay (match-beginning 0) (match-end 0)))) - (overlay-put overlay 'display (propertize "****" - 'face 'warning)) - (overlay-put overlay 'reveal-toggle-invisible - #'authinfo--toggle-display))))))) - -(defun authinfo--toggle-display (overlay hide) - (if hide - (overlay-put overlay 'display (propertize "****" 'face 'warning)) - (overlay-put overlay 'display nil))) +(defun auth-source-reveal-compose-p (start end _match) + "Return true iff the symbol MATCH should be composed. +The symbol starts at position START and ends at position END. +This overrides the default for `prettify-symbols-compose-predicate'." + ;; Check that the chars should really be composed into a symbol. + t) + +;;;###autoload +(define-minor-mode auth-source-reveal-mode + "Toggle password hiding for auth-source files using `prettify-symbols-mode'. + +If called interactively, enable auth-source-reveal mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is toggle; disable the mode otherwise. + +When auth-source-reveal mode is enabled, passwords will be +hidden. To reveal them when point is inside them, see +`prettify-symbols-unprettify-at-point'. + +See `auth-source-password-hide-regex' for the regex matching the +tokens and keys associated with passwords." + ;; The initial value. + :init-value nil + ;; The indicator for the mode line. + :lighter " asr" + :group 'auth-source + + (when auth-source-reveal-mode + ;; Install the prettification magic. + (prettify-symbols-add-prettification-rx + 'auth-source-reveal-mode-prettify-regexp ; The identifier symbol. + ;; regexp to hide/reveal + (if (apply #'derived-mode-p auth-source-reveal-json-modes) + (format "\"?password\"?[:[:blank:]]+\"\\([^\t\r\n\"]+\\)\"" auth-source-reveal-regex) + (format "\\b%s\\b\\s-+\\([^ \t\r\n]+\\)" auth-source-reveal-regex)) + auth-source-reveal-hider) + + (setq-local + prettify-symbols-compose-predicate #'auth-source-reveal-compose-p) + (unless prettify-symbols-unprettify-at-point + (auth-source-do-warn + "Please set `%s' to _see_ passwords at point" + 'prettify-symbols-unprettify-at-point))) + + (prettify-symbols-mode (if auth-source-reveal-mode 1 -1))) + +(defun turn-on-auth-source-reveal-mode () + (when (and (not auth-source-reveal-mode) + (local-variable-p 'prettify-symbols-alist)) + (auth-source-reveal-mode 1))) (provide 'auth-source) -- 2.39.2