diff options
-rw-r--r-- | contrib/dmenu/README.md | 7 | ||||
-rwxr-xr-x | contrib/dmenu/passmenu | 16 | ||||
-rw-r--r-- | contrib/emacs/CHANGELOG.md | 22 | ||||
-rw-r--r-- | contrib/emacs/Cask | 3 | ||||
-rw-r--r-- | contrib/emacs/README.md | 8 | ||||
-rw-r--r-- | contrib/emacs/password-store.el | 154 | ||||
-rw-r--r-- | contrib/vim/redact_pass.vim | 7 | ||||
-rw-r--r-- | src/completion/pass.bash-completion | 2 | ||||
-rw-r--r-- | src/completion/pass.fish-completion | 30 | ||||
-rw-r--r-- | src/completion/pass.zsh-completion | 2 | ||||
-rwxr-xr-x | src/password-store.sh | 26 | ||||
-rw-r--r-- | src/platform/darwin.sh | 2 | ||||
-rw-r--r-- | tests/gnupg/gpg.conf | 6 | ||||
-rw-r--r-- | tests/setup.sh | 12 | ||||
-rwxr-xr-x | tests/t0020-show-tests.sh | 5 |
15 files changed, 201 insertions, 101 deletions
diff --git a/contrib/dmenu/README.md b/contrib/dmenu/README.md index 9d54fb4..8a196cb 100644 --- a/contrib/dmenu/README.md +++ b/contrib/dmenu/README.md @@ -4,6 +4,10 @@ clipboard without having to open up a terminal window if you don't already have one open. If `--type` is specified, the password is typed using [xdotool][] instead of copied to the clipboard. +On wayland [dmenu-wl][] is used to replace dmenu and [ydotool][] to replace xdotool. +Note that the latter requires access to the [uinput][] device, so you'll probably +need to add an extra udev rule or similar to give certain non-root users permission. + # Usage passmenu [--type] [dmenu arguments...] @@ -11,3 +15,6 @@ instead of copied to the clipboard. [dmenu]: http://tools.suckless.org/dmenu/ [xdotool]: http://www.semicomplete.com/projects/xdotool/ [pass]: http://www.zx2c4.com/projects/password-store/ +[dmenu-wl]: https://github.com/nyyManni/dmenu-wayland +[ydotool]: https://github.com/ReimuNotMoe/ydotool +[uinput]: https://www.kernel.org/doc/html/v4.12/input/uinput.html diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu index 83268bc..76d92ab 100755 --- a/contrib/dmenu/passmenu +++ b/contrib/dmenu/passmenu @@ -8,18 +8,28 @@ if [[ $1 == "--type" ]]; then shift fi +if [[ -n $WAYLAND_DISPLAY ]]; then + dmenu=dmenu-wl + xdotool="ydotool type --file -" +elif [[ -n $DISPLAY ]]; then + dmenu=dmenu + xdotool="xdotool type --clearmodifiers --file -" +else + echo "Error: No Wayland or X11 display detected" >&2 + exit 1 +fi + prefix=${PASSWORD_STORE_DIR-~/.password-store} password_files=( "$prefix"/**/*.gpg ) password_files=( "${password_files[@]#"$prefix"/}" ) password_files=( "${password_files[@]%.gpg}" ) -password=$(printf '%s\n' "${password_files[@]}" | dmenu "$@") +password=$(printf '%s\n' "${password_files[@]}" | "$dmenu" "$@") [[ -n $password ]] || exit if [[ $typeit -eq 0 ]]; then pass show -c "$password" 2>/dev/null else - pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | - xdotool type --clearmodifiers --file - + pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | $xdotool fi diff --git a/contrib/emacs/CHANGELOG.md b/contrib/emacs/CHANGELOG.md index 7173f65..e15414f 100644 --- a/contrib/emacs/CHANGELOG.md +++ b/contrib/emacs/CHANGELOG.md @@ -1,3 +1,25 @@ +# 2.3.2 + +* (bugfix) Ensure the system clipboard is cleared after + the timeout expired. + +# 2.3.1 + +* (bug) Drop dependency on s library. + +# 2.3.0 + +* (bug) Drop auth-source-pass dependency. + Bump Emacs minor version requirement to emacs 26. + +# 2.2.0 + +* (feature) Add command password-store-generate-no-symbols + +# 2.1.5 + +* (bugfix) Fix an infloop on Windows enviroments. + # 2.1.4 * Drop dependency on f library. diff --git a/contrib/emacs/Cask b/contrib/emacs/Cask index 050e054..1d8ce9f 100644 --- a/contrib/emacs/Cask +++ b/contrib/emacs/Cask @@ -7,5 +7,4 @@ (depends-on "with-editor") (depends-on "ecukes") (depends-on "ert-runner") - (depends-on "el-mock") - (depends-on "auth-source-pass")) + (depends-on "el-mock")) diff --git a/contrib/emacs/README.md b/contrib/emacs/README.md index d3679e9..8269c35 100644 --- a/contrib/emacs/README.md +++ b/contrib/emacs/README.md @@ -19,6 +19,14 @@ Interactive: Password: ........ Confirm password: ........ + ;; Generate a random password. + M-x password-store-generate + Password entry: bar-account + + ;; Generate a random password without symbols. + M-x password-store-generate-no-symbols + Password entry: qux-account + M-x password-store-copy Password entry: foo-account Copied password for foo-account to the kill ring. Will clear in 45 seconds. diff --git a/contrib/emacs/password-store.el b/contrib/emacs/password-store.el index 61c339e..c7cc991 100644 --- a/contrib/emacs/password-store.el +++ b/contrib/emacs/password-store.el @@ -4,32 +4,34 @@ ;; Author: Svend Sorensen <svend@svends.net> ;; Maintainer: Tino Calancha <tino.calancha@gmail.com> -;; Version: 2.1.4 +;; Version: 2.3.2 ;; URL: https://www.passwordstore.org/ -;; Package-Requires: ((emacs "25") (s "1.9.0") (with-editor "2.5.11") (auth-source-pass "5.0.0")) -;; Keywords: tools pass password password-store +;; Package-Requires: ((emacs "26.1") (with-editor "2.5.11")) +;; SPDX-License-Identifier: GPL-3.0-or-later +;; Keywords: tools pass password password-store gpg ;; This file is not part of GNU Emacs. -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. +;; This program is free software: you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation, either version 3 of +;; the License, or (at your option) any later version. -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. +;; This program is distributed in the hope that it will be +;; useful, but WITHOUT ANY WARRANTY; without even the implied +;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +;; PURPOSE. See the GNU General Public License for more details. -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see <http://www.gnu.org/licenses/>. +;; You should have received a copy of the GNU General Public +;; License along with this program. If not, see +;; <http://www.gnu.org/licenses/>. ;;; Commentary: -;; This package provides functions for working with pass ("the -;; standard Unix password manager"). -;; -;; http://www.passwordstore.org/ +;; This package provides and Emacs interface for working with +;; pass ("the standard Unix password manager"). + +;; https://www.passwordstore.org/ ;;; Code: @@ -37,9 +39,17 @@ (require 'auth-source-pass) (defgroup password-store '() - "Emacs mode for password-store." + "Emacs mode for password-store. +The standard Unix password manager" :prefix "password-store-" - :group 'password-store) + :group 'password-store + :link '(url-link :tag "Description" "https://www.passwordstore.org/") + :link '(url-link :tag "Download" "https://melpa.org/#/password-store") + :link `(url-link :tag "Send Bug Report" + ,(concat "mailto:" "password-store" "@" "lists.zx2c4" ".com?subject= +password-store.el bug: \ +&body=Describe bug here, starting with `emacs -q'. \ +Don't forget to mention your Emacs and library versions."))) (defcustom password-store-password-length 25 "Default password length." @@ -55,7 +65,7 @@ :type 'number) (defcustom password-store-url-field "url" - "Field name used in the files to indicate an url." + "Field name used in the files to indicate a URL." :group 'password-store :type 'string) @@ -67,17 +77,20 @@ "Timer for clearing clipboard.") (defun password-store-timeout () - "Number of seconds to wait before clearing the password. + "Number of seconds to wait before restoring the clipboard. + +This function just returns +`password-store-time-before-clipboard-restore'. Kept for +backward compatibility with other libraries." +password-store-time-before-clipboard-restore) -This function just returns `password-store-time-before-clipboard-restore'. -Kept for backward compatibility with other libraries." - password-store-time-before-clipboard-restore) +(make-obsolete 'password-store-timeout 'password-store-time-before-clipboard-restore "2.0.4") (defun password-store--run-1 (callback &rest args) "Run pass with ARGS. -Nil arguments are ignored. Calls CALLBACK with the output on success, -or outputs error message on failure." +Nil arguments are ignored. Calls CALLBACK with the output on +success, or outputs error message on failure." (let ((output "")) (make-process :name "password-store-gpg" @@ -88,9 +101,10 @@ or outputs error message on failure." (setq output (concat output text))) :sentinel (lambda (process state) (cond - ((string= state "finished\n") + ((and (eq (process-status process) 'exit) + (zerop (process-exit-status process))) (funcall callback output)) - ((string= state "open\n") (accept-process-output process)) + ((eq (process-status process) 'run) (accept-process-output process)) (t (error (concat "password-store: " state)))))))) (defun password-store--run (&rest args) @@ -117,9 +131,9 @@ Nil arguments are ignored. Output is discarded." (cons password-store-executable (delq nil args)) " ")))) -(defun password-store--run-init (gpg-ids &optional folder) +(defun password-store--run-init (gpg-ids &optional subdir) (apply 'password-store--run "init" - (if folder (format "--path=%s" folder)) + (if subdir (format "--path=%s" subdir)) gpg-ids)) (defun password-store--run-list (&optional subdir) @@ -229,8 +243,8 @@ ENTRY is the name of a password-store entry." (defun password-store-get (entry &optional callback) "Return password for ENTRY. -Returns the first line of the password data. -When CALLBACK is non-`NIL', call CALLBACK with the first line instead." +Returns the first line of the password data. When CALLBACK is +non-`NIL', call CALLBACK with the first line instead." (let* ((inhibit-message t) (secret (auth-source-pass-get 'secret entry))) (if (not callback) secret @@ -241,9 +255,10 @@ When CALLBACK is non-`NIL', call CALLBACK with the first line instead." ;;;###autoload (defun password-store-get-field (entry field &optional callback) "Return FIELD for ENTRY. -FIELD is a string, for instance \"url\". -When CALLBACK is non-`NIL', call it with the line associated to FIELD instead. -If FIELD equals to symbol secret, then this function reduces to `password-store-get'." +FIELD is a string, for instance \"url\". When CALLBACK is +non-`NIL', call it with the line associated to FIELD instead. If +FIELD equals to symbol secret, then this function reduces to +`password-store-get'." (let* ((inhibit-message t) (secret (auth-source-pass-get field entry))) (if (not callback) secret @@ -256,12 +271,12 @@ If FIELD equals to symbol secret, then this function reduces to `password-store- (defun password-store-clear (&optional field) "Clear secret in the kill ring. -Optional argument FIELD, a symbol or a string, describes -the stored secret to clear; if nil, then set it to 'secret. -Note, FIELD does not affect the function logic; it is only used -to display the message: +Optional argument FIELD, a symbol or a string, describes the +stored secret to clear; if nil, then set it to 'secret. Note, +FIELD does not affect the function logic; it is only used to +display the message: -\(message \"Field %s cleared.\" field)." +\(message \"Field %s cleared from kill ring and system clipboard.\" field)." (interactive "i") (unless field (setq field 'secret)) (when password-store-timeout-timer @@ -269,14 +284,15 @@ to display the message: (setq password-store-timeout-timer nil)) (when password-store-kill-ring-pointer (setcar password-store-kill-ring-pointer "") + (kill-new "") (setq password-store-kill-ring-pointer nil) - (message "Field %s cleared." field))) + (message "Field %s cleared from kill ring and system clipboard." field))) (defun password-store--save-field-in-kill-ring (entry secret field) (password-store-clear field) (kill-new secret) (setq password-store-kill-ring-pointer kill-ring-yank-pointer) - (message "Copied %s for %s to the kill ring. Will clear in %s seconds." + (message "Copied %s for %s to the kill ring and system clipboard. Will clear in %s seconds." field entry password-store-time-before-clipboard-restore) (setq password-store-timeout-timer (run-at-time password-store-time-before-clipboard-restore nil @@ -286,9 +302,10 @@ to display the message: (defun password-store-copy (entry) "Add password for ENTRY into the kill ring. -Clear previous password from the kill ring. Pointer to the kill ring -is stored in `password-store-kill-ring-pointer'. Password is cleared -after `password-store-time-before-clipboard-restore' seconds." +Clear previous password from the kill ring. Pointer to the kill +ring is stored in `password-store-kill-ring-pointer'. Password +is cleared after `password-store-time-before-clipboard-restore' +seconds." (interactive (list (password-store--completing-read t))) (password-store-get entry @@ -299,10 +316,12 @@ after `password-store-time-before-clipboard-restore' seconds." (defun password-store-copy-field (entry field) "Add FIELD for ENTRY into the kill ring. -Clear previous secret from the kill ring. Pointer to the kill ring is -stored in `password-store-kill-ring-pointer'. Secret field is cleared -after `password-store-timeout' seconds. -If FIELD equals to symbol secret, then this function reduces to `password-store-copy'." +Clear previous secret from the kill ring. Pointer to the kill +ring is stored in `password-store-kill-ring-pointer'. Secret +field is cleared after +`password-store-time-before-clipboard-restore' seconds. If FIELD +equals to symbol secret, then this function reduces to +`password-store-copy'." (interactive (let ((entry (password-store--completing-read))) (list entry (password-store-read-field entry)))) @@ -341,17 +360,36 @@ Separate multiple IDs with spaces." Default PASSWORD-LENGTH is `password-store-password-length'." (interactive (list (password-store--completing-read) - (when current-prefix-arg - (abs (prefix-numeric-value current-prefix-arg))))) - (unless password-length (setq password-length password-store-password-length)) - ;; A message with the output of the command is not printed because - ;; the output contains the password. - (password-store--run-generate entry password-length t) + (and current-prefix-arg + (abs (prefix-numeric-value current-prefix-arg))))) + ;; A message with the output of the command is not printed + ;; because the output contains the password. + (password-store--run-generate + entry + (or password-length password-store-password-length) + 'force) + nil) + +;;;###autoload +(defun password-store-generate-no-symbols (entry &optional password-length) + "Generate a new password without symbols for ENTRY with PASSWORD-LENGTH. + +Default PASSWORD-LENGTH is `password-store-password-length'." + (interactive (list (password-store--completing-read) + (and current-prefix-arg + (abs (prefix-numeric-value current-prefix-arg))))) + + ;; A message with the output of the command is not printed + ;; because the output contains the password. + (password-store--run-generate + entry + (or password-length password-store-password-length) + 'force 'no-symbols) nil) ;;;###autoload (defun password-store-remove (entry) - "Remove existing password for ENTRY." + "Remove ENTRY." (interactive (list (password-store--completing-read t))) (message "%s" (password-store--run-remove entry t))) @@ -364,13 +402,13 @@ Default PASSWORD-LENGTH is `password-store-password-length'." ;;;###autoload (defun password-store-version () - "Show version of pass executable." + "Show version of `password-store-executable'." (interactive) (message "%s" (password-store--run-version))) ;;;###autoload (defun password-store-url (entry) - "Browse URL stored in ENTRY." + "Load URL for ENTRY." (interactive (list (password-store--completing-read t))) (let ((url (password-store-get-field entry password-store-url-field))) (if url (browse-url url) diff --git a/contrib/vim/redact_pass.vim b/contrib/vim/redact_pass.vim index a3d67e8..2e752fe 100644 --- a/contrib/vim/redact_pass.vim +++ b/contrib/vim/redact_pass.vim @@ -35,6 +35,7 @@ function! s:CheckArgsRedact() " Tell the user what we're doing so they know this worked, via a message and " a global variable they can check + redraw echomsg 'Editing password file--disabled leaky options!' let g:redact_pass_redacted = 1 @@ -48,4 +49,10 @@ augroup redact_pass \,$TMPDIR/pass.?*/?*.txt \,/tmp/pass.?*/?*.txt \ call s:CheckArgsRedact() + " Work around macOS' dynamic symlink structure for temporary directories + if has('mac') + autocmd VimEnter + \ /private/var/?*/pass.?*/?*.txt + \ call s:CheckArgsRedact() + endif augroup END diff --git a/src/completion/pass.bash-completion b/src/completion/pass.bash-completion index 95d3e1e..2d23cbf 100644 --- a/src/completion/pass.bash-completion +++ b/src/completion/pass.bash-completion @@ -72,7 +72,7 @@ _pass_complete_folders () { _pass_complete_keys () { local GPG="gpg" - which gpg2 &>/dev/null && GPG="gpg2" + command -v gpg2 &>/dev/null && GPG="gpg2" local IFS=$'\n' # Extract names and email addresses from gpg --list-keys diff --git a/src/completion/pass.fish-completion b/src/completion/pass.fish-completion index 0c67bf3..0f57dd2 100644 --- a/src/completion/pass.fish-completion +++ b/src/completion/pass.fish-completion @@ -1,16 +1,14 @@ -#!/usr/bin/env fish - # Copyright (C) 2012-2014 Dmitry Medvinsky <me@dmedvinsky.name>. All Rights Reserved. # This file is licensed under the GPLv2+. Please see COPYING for more information. set -l PROG 'pass' function __fish_pass_get_prefix - set -l prefix "$PASSWORD_STORE_DIR" - if [ -z "$prefix" ] - set prefix "$HOME/.password-store" + if set -q PASSWORD_STORE_DIR + realpath -- "$PASSWORD_STORE_DIR" + else + echo "$HOME/.password-store" end - echo "$prefix" end function __fish_pass_needs_command @@ -52,6 +50,12 @@ function __fish_pass_print_entries_and_dirs __fish_pass_print_entries end +function __fish_pass_git_complete + set -l prefix (__fish_pass_get_prefix) + set -l git_cmd (commandline -opc) (commandline -ct) + set -e git_cmd[1 2] # Drop "pass git". + complete -C"git -C $prefix $git_cmd" +end complete -c $PROG -f -n '__fish_pass_needs_command' -a help -d 'Command: show usage help' complete -c $PROG -f -n '__fish_pass_needs_command' -a version -d 'Command: show program version' @@ -101,13 +105,11 @@ complete -c $PROG -f -n '__fish_pass_uses_command -c' -a "(__fish_pass_print_ent complete -c $PROG -f -n '__fish_pass_uses_command --clip' -a "(__fish_pass_print_entries)" complete -c $PROG -f -n '__fish_pass_needs_command' -a git -d 'Command: execute a git command' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'init' -d 'Initialize git repository' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'status' -d 'Show status of the repo' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'add' -d 'Add changes to the index' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'commit' -d 'Commit changes to the repo' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'push' -d 'Push changes to remote repo' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'pull' -d 'Pull changes from remote repo' -complete -c $PROG -f -n '__fish_pass_uses_command git' -a 'log' -d 'View changelog' - +complete -c $PROG -f -n '__fish_pass_uses_command git' -a '(__fish_pass_git_complete)' complete -c $PROG -f -n '__fish_pass_needs_command' -a find -d 'Command: find a password file or directory matching pattern' complete -c $PROG -f -n '__fish_pass_needs_command' -a grep -d 'Command: search inside of decrypted password files for matching pattern' +complete -c $PROG -f -n '__fish_pass_uses_command grep' -a '(begin + set -l cmd (commandline -opc) (commandline -ct) + set -e cmd[1 2] # Drop "pass grep". + complete -C"grep $cmd" +end)' diff --git a/src/completion/pass.zsh-completion b/src/completion/pass.zsh-completion index 27ce15a..d911e12 100644 --- a/src/completion/pass.zsh-completion +++ b/src/completion/pass.zsh-completion @@ -124,7 +124,7 @@ _pass_complete_entries_helper () { local IFS=$'\n' local prefix zstyle -s ":completion:${curcontext}:" prefix prefix || prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}" - _values -C 'passwords' ${$(find -L "$prefix" \( -name .git -o -name .gpg-id \) -prune -o $@ -print 2>/dev/null | sed -e "s#${prefix}/\{0,1\}##" -e 's#\.gpg##' -e 's#\\#\\\\#' | sort):-""} + _values -C 'passwords' ${$(find -L "$prefix" \( -name .git -o -name .gpg-id \) -prune -o $@ -print 2>/dev/null | sed -e "s#${prefix}/\{0,1\}##" -e 's#\.gpg##' -e 's#\\#\\\\#g' -e 's#:#\\:#g' | sort):-""} } _pass_complete_entries_with_subdirs () { diff --git a/src/password-store.sh b/src/password-store.sh index 77f3eda..22e818f 100755 --- a/src/password-store.sh +++ b/src/password-store.sh @@ -9,7 +9,7 @@ set -o pipefail GPG_OPTS=( $PASSWORD_STORE_GPG_OPTS "--quiet" "--yes" "--compress-algo=none" "--no-encrypt-to" ) GPG="gpg" export GPG_TTY="${GPG_TTY:-$(tty 2>/dev/null)}" -which gpg2 &>/dev/null && GPG="gpg2" +command -v gpg2 &>/dev/null && GPG="gpg2" [[ -n $GPG_AGENT_INFO || $GPG == "gpg2" ]] && GPG_OPTS+=( "--batch" "--use-agent" ) PREFIX="${PASSWORD_STORE_DIR:-$HOME/.password-store}" @@ -70,6 +70,7 @@ verify_file() { set_gpg_recipients() { GPG_RECIPIENT_ARGS=( ) GPG_RECIPIENTS=( ) + local gpg_id if [[ -n $PASSWORD_STORE_KEY ]]; then for gpg_id in $PASSWORD_STORE_KEY; do @@ -98,8 +99,9 @@ set_gpg_recipients() { verify_file "$current" - local gpg_id while read -r gpg_id; do + gpg_id="${gpg_id%%#*}" # strip comment + [[ -n $gpg_id ]] || continue GPG_RECIPIENT_ARGS+=( "-r" "$gpg_id" ) GPG_RECIPIENTS+=( "$gpg_id" ) done < "$current" @@ -127,7 +129,7 @@ reencrypt_path() { done gpg_keys="$($GPG $PASSWORD_STORE_GPG_OPTS --list-keys --with-colons "${GPG_RECIPIENTS[@]}" | sed -n 's/^sub:[^idr:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u)" fi - current_keys="$(LC_ALL=C $GPG $PASSWORD_STORE_GPG_OPTS -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$passfile" 2>&1 | sed -n 's/^gpg: public key is \([A-F0-9]\+\)$/\1/p' | LC_ALL=C sort -u)" + current_keys="$(LC_ALL=C $GPG $PASSWORD_STORE_GPG_OPTS -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$passfile" 2>&1 | sed -nE 's/^gpg: public key is ([A-F0-9]+)$/\1/p' | LC_ALL=C sort -u)" if [[ $gpg_keys != "$current_keys" ]]; then echo "$passfile_display: reencrypting to ${gpg_keys//$'\n'/ }" @@ -135,7 +137,7 @@ reencrypt_path() { mv "$passfile_temp" "$passfile" || rm -f "$passfile_temp" fi prev_gpg_recipients="${GPG_RECIPIENTS[*]}" - done < <(find "$1" -path '*/.git' -prune -o -iname '*.gpg' -print0) + done < <(find "$1" -path '*/.git' -prune -o -path '*/.extensions' -prune -o -iname '*.gpg' -print0) } check_sneaky_paths() { local path @@ -153,7 +155,7 @@ check_sneaky_paths() { # clip() { - if [[ -n $WAYLAND_DISPLAY ]]; then + if [[ -n $WAYLAND_DISPLAY ]] && command -v wl-copy &> /dev/null; then local copy_cmd=( wl-copy ) local paste_cmd=( wl-paste -n ) if [[ $X_SELECTION == primary ]]; then @@ -161,12 +163,12 @@ clip() { paste_cmd+=( --primary ) fi local display_name="$WAYLAND_DISPLAY" - elif [[ -n $DISPLAY ]]; then + elif [[ -n $DISPLAY ]] && command -v xclip &> /dev/null; then local copy_cmd=( xclip -selection "$X_SELECTION" ) local paste_cmd=( xclip -o -selection "$X_SELECTION" ) local display_name="$DISPLAY" else - die "Error: No X11 or Wayland display detected" + die "Error: No X11 or Wayland display and clipper detected" fi local sleep_argv0="password store sleep on display $display_name" @@ -260,7 +262,7 @@ cmd_version() { ============================================ = pass: the standard unix password manager = = = - = v1.7.3 = + = v1.7.4 = = = = Jason A. Donenfeld = = Jason@zx2c4.com = @@ -353,7 +355,7 @@ cmd_init() { signing_keys+=( --default-key $key ) done $GPG "${GPG_OPTS[@]}" "${signing_keys[@]}" --detach-sign "$gpg_id" || die "Could not sign .gpg_id." - key="$($GPG --verify --status-fd=1 "$gpg_id.sig" "$gpg_id" 2>/dev/null | sed -n 's/^\[GNUPG:\] VALIDSIG [A-F0-9]\{40\} .* \([A-F0-9]\{40\}\)$/\1/p')" + key="$($GPG "${GPG_OPTS[@]}" --verify --status-fd=1 "$gpg_id.sig" "$gpg_id" 2>/dev/null | sed -n 's/^\[GNUPG:\] VALIDSIG [A-F0-9]\{40\} .* \([A-F0-9]\{40\}\)$/\1/p')" [[ -n $key ]] || die "Signing of .gpg_id unsuccessful." git_add_file "$gpg_id.sig" "Signing new GPG id with ${key//[$IFS]/,}." fi @@ -400,7 +402,7 @@ cmd_show() { else echo "${path%\/}" fi - tree -C -l --noreport "$PREFIX/$path" | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' # remove .gpg at end of line, but keep colors + tree -N -C -l --noreport "$PREFIX/$path" 3>&- | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' # remove .gpg at end of line, but keep colors elif [[ -z $path ]]; then die "Error: password store is empty. Try \"pass init\"." else @@ -412,7 +414,7 @@ cmd_find() { [[ $# -eq 0 ]] && die "Usage: $PROGRAM $COMMAND pass-names..." IFS="," eval 'echo "Search Terms: $*"' local terms="*$(printf '%s*|*' "$@")" - tree -C -l --noreport -P "${terms%|*}" --prune --matchdirs --ignore-case "$PREFIX" | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' + tree -N -C -l --noreport -P "${terms%|*}" --prune --matchdirs --ignore-case "$PREFIX" 3>&- | tail -n +2 | sed -E 's/\.gpg(\x1B\[[0-9]+m)?( ->|$)/\1\2/g' } cmd_grep() { @@ -428,7 +430,7 @@ cmd_grep() { passfile="${passfile##*/}" printf "\e[94m%s\e[1m%s\e[0m:\n" "$passfile_dir" "$passfile" echo "$grepresults" - done < <(find -L "$PREFIX" -path '*/.git' -prune -o -iname '*.gpg' -print0) + done < <(find -L "$PREFIX" -path '*/.git' -prune -o -path '*/.extensions' -prune -o -iname '*.gpg' -print0) } cmd_insert() { diff --git a/src/platform/darwin.sh b/src/platform/darwin.sh index f6cc471..9a1fda8 100644 --- a/src/platform/darwin.sh +++ b/src/platform/darwin.sh @@ -39,6 +39,6 @@ qrcode() { fi } -GETOPT="$({ test -x /usr/local/opt/gnu-getopt/bin/getopt && echo /usr/local/opt/gnu-getopt; } || brew --prefix gnu-getopt 2>/dev/null || { which port &>/dev/null && echo /opt/local; } || echo /usr/local)/bin/getopt" +GETOPT="$({ test -x /usr/local/opt/gnu-getopt/bin/getopt && echo /usr/local/opt/gnu-getopt; } || brew --prefix gnu-getopt 2>/dev/null || { command -v port &>/dev/null && echo /opt/local; } || echo /usr/local)/bin/getopt" SHRED="srm -f -z" BASE64="openssl base64" diff --git a/tests/gnupg/gpg.conf b/tests/gnupg/gpg.conf index 60ece49..67daa58 100644 --- a/tests/gnupg/gpg.conf +++ b/tests/gnupg/gpg.conf @@ -1,3 +1,3 @@ -group group1 = E4691410 D774A374 -group group2 = E4691410 -group big group = CF90C77B D774A374 EB7D54A8 E4691410 39E5020C +group group1 = 9378267629F989A0E96677B7976DD3D6E4691410 70BD448330ACF0653645B8F2B4DDBFF0D774A374 +group group2 = 9378267629F989A0E96677B7976DD3D6E4691410 +group big group = D4C78DB7920E1E27F5416B81CC9DB947CF90C77B 70BD448330ACF0653645B8F2B4DDBFF0D774A374 62EBE74BE834C2EC71E6414595C4B715EB7D54A8 9378267629F989A0E96677B7976DD3D6E4691410 4D2AFBDE67C60F5999D143AFA6E073D439E5020C diff --git a/tests/setup.sh b/tests/setup.sh index 5d1e794..058ce0a 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -52,13 +52,13 @@ fi export GNUPGHOME="$TEST_HOME/gnupg/" chmod 700 "$GNUPGHOME" GPG="gpg" -which gpg2 &>/dev/null && GPG="gpg2" +command -v gpg2 &>/dev/null && GPG="gpg2" # We don't want any currently running agent to conflict. unset GPG_AGENT_INFO -KEY1="CF90C77B" # pass test key 1 -KEY2="D774A374" # pass test key 2 -KEY3="EB7D54A8" # pass test key 3 -KEY4="E4691410" # pass test key 4 -KEY5="39E5020C" # pass test key 5 +KEY1="D4C78DB7920E1E27F5416B81CC9DB947CF90C77B" # pass test key 1 +KEY2="70BD448330ACF0653645B8F2B4DDBFF0D774A374" # pass test key 2 +KEY3="62EBE74BE834C2EC71E6414595C4B715EB7D54A8" # pass test key 3 +KEY4="9378267629F989A0E96677B7976DD3D6E4691410" # pass test key 4 +KEY5="4D2AFBDE67C60F5999D143AFA6E073D439E5020C" # pass test key 5 diff --git a/tests/t0020-show-tests.sh b/tests/t0020-show-tests.sh index a4b782f..81b87b4 100755 --- a/tests/t0020-show-tests.sh +++ b/tests/t0020-show-tests.sh @@ -15,6 +15,11 @@ test_expect_success 'Test "show" command with spaces' ' [[ $("$PASS" show "I am a cred with lots of spaces") == "BLAH!!" ]] ' +test_expect_success 'Test "show" command with unicode' ' + "$PASS" generate 🏠 && + "$PASS" show | grep -q '🏠' +' + test_expect_success 'Test "show" of nonexistant password' ' test_must_fail "$PASS" show cred2 ' |