summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbzp99 <bertalanp99+git@bertalanp99.eu>2020-06-04 15:36:28 +0200
committerbzp99 <bertalanp99+git@bertalanp99.eu>2020-06-04 15:36:28 +0200
commite72bd1b0411455649f3e8ed54941e80165c2dc11 (patch)
tree0d8d5b0bc8c5cee6f2ecd53df51a5d4ead8b52ec
downloadpassmenu-e72bd1b0411455649f3e8ed54941e80165c2dc11.tar.gz
passmenu-e72bd1b0411455649f3e8ed54941e80165c2dc11.zip
initial commit
-rw-r--r--README15
-rwxr-xr-xpassmenu155
-rw-r--r--passmenu.189
-rwxr-xr-xpassmenu.sh134
4 files changed, 393 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..e03dab6
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
+= passmenu
+Bertalan Z. Péter <bp99@bp99.eu>
+v0.1, 2020-06-04
+
+Interactive frontend to https://www.passwordstore.org/[password-store] using
+whatever you have:
+
+* rofi or dmenu in X
+* fzf in a shell session
+
+Also copies the selected password to the X primary selection.
+
+WARNING: The main script is called `passmenu`. Scripts you find with other
+extensions, such as `passmenu.sh` are different implementations and are not
+guaranteed to either work or be complete.
diff --git a/passmenu b/passmenu
new file mode 100755
index 0000000..9c83324
--- /dev/null
+++ b/passmenu
@@ -0,0 +1,155 @@
+#!/usr/bin/perl
+
+# Copyright (c) 2020, Bertalan Zoltán Péter <bp99@bp99.eu>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+use 5.30.1;
+use strict;
+use warnings;
+use diagnostics;
+use experimental qw(smartmatch);
+use Clipboard;
+use File::Find qw(find);
+use Getopt::Long;
+use Pod::Usage qw(pod2usage);
+use constant VERSION => 'passmenu v0.1';
+
+
+my ($gui, $dmenu, $login, $print, $help, $man, $version) = (0) x 7;
+# Getopt::Long::Configure('auto_version');
+GetOptions('gui' => \$gui,
+ 'dmenu' => \$dmenu,
+ 'login' => \$login,
+ 'print' => \$print,
+ 'help' => \$help,
+ 'man' => \$man,
+ 'version' => \$version) or pod2usage 2;
+
+if ($version) { say VERSION; exit; }
+pod2usage -verbose => 1 if $help;
+pod2usage -verbose => 2 if $man;
+
+
+my $cli = -t STDIN ? ($gui ? 0 : 1) : 0;
+
+! system 'pass version >/dev/null 2>&1' or die "I couldn't find password-store";
+
+my $menu;
+if (not $cli) {
+ my $dmenu_ = ! system 'dmenu -v >/dev/null 2>&1';
+ my $rofi_ = ! system 'rofi -v >/dev/null 2>&1';
+ die "I couldn't find either rofi or dmenu" if not $dmenu_ and not $rofi_;
+ die "I coudln't find dmenu" if $dmenu and not $dmenu_;
+ $menu = $dmenu ? 'dmenu' : ($rofi_ ? 'rofi' : 'dmenu');
+} else {
+ my $fzf_ = ! system 'fzf --version >/dev/null 2>&1';
+ $menu = $fzf_ ? 'fzf' : 'internal';
+}
+
+my $dir = "$ENV{HOME}/.password-store/";
+my @files;
+find sub {
+ return if substr($_, -4, 4) ne '.gpg';
+ push @files, $File::Find::name; }, $dir;
+@files = map { (my $f = $_ ) =~ s/^$dir//; $f =~ s/\.gpg//; $f } @files;
+
+my $choice;
+if ($menu eq 'internal') {
+ print 'query: ';
+ my $query = <STDIN>;
+ chomp $query;
+
+ my @result = grep { /$query/ } @files;
+ say $_ + 1, "\t", $result[$_] for (0 .. $#result);
+
+ my $n;
+ do {
+ print 'selection: ';
+ $n = <STDIN>;
+ chomp $n;
+ } while ! $n || ! grep { /$n/ } (0 .. $#result);
+
+ $choice = $result[$n - 1];
+} else {
+ my $filelist = join "\\n", @files;
+ if ($menu eq 'dmenu') {
+ $choice = `echo "$filelist" | dmenu -i`;
+ } elsif ($menu eq 'rofi') {
+ $choice = `echo "$filelist" | rofi -dmenu -p pass -i`;
+ } elsif ($menu eq 'fzf') {
+ $choice = `echo "$filelist" | fzf --height=8`;
+ }
+}
+
+chomp $choice;
+my $pass = `pass show '$choice'`;
+if ($login) {
+ $pass =~ s/.*login: (.+)\n.*/$1/s;
+} else {
+ $pass =~ s/\n.*//s;
+}
+
+if (index($pass, "\n") != -1) {
+ if ($cli) {
+ die 'Result continains newline, aborting';
+ } else {
+ system "xmessage -center -default okay 'Result continains newline, aborting'";
+ }
+}
+Clipboard->copy($pass);
+
+
+__END__
+
+=encoding utf8
+=head1 NAME
+
+passmenu - Handy password-store frontend
+
+=head1 SYNOPSIS
+
+passmenu [options]
+
+ Options:
+ -g, --gui force dmenu or rofi, even if called from terminal
+ -d, --dmenu force dmenu even if rofi exists
+ -l, --login copy the username, not the password
+ -p, --print instead of copying, print the value
+ -h, --help display this help message
+ -m, --man open the manual
+ -v, --version print programme version
+
+=head1 DESCRIPTION
+
+This programme is designed to ease the use of password-store (or pass
+for short).
+
+When you are in a terminal, passmenu will prompt you for a query string
+either using fzf if you have it, or using a less fancy internal method.
+
+When called from anywhere else (e.g. launched by dmenu or by your
+window manager), it will display a prompt either using dmenu or,
+preferably, rofi.
+
+Therefore you must have either rofi or dmenu to use passmenu outside a
+terminal.
+
+Once you select a pass entry using the menu, it will be copied to the
+clipboard for you to do whatever you want with it.
+
+=head1 AUTHOR
+
+Bertalan Z. Péter <bp99@bp99.eu>
+
+=cut
diff --git a/passmenu.1 b/passmenu.1
new file mode 100644
index 0000000..399ae3a
--- /dev/null
+++ b/passmenu.1
@@ -0,0 +1,89 @@
+.\"""
+.\" passmenu.1 - passmenu man page
+.\"
+.\" bertalanp99@ 2019-05-20
+.\"""
+.Dd 2019-05-20
+.Dt PASSMENU 1
+.Os
+.Sh NAME
+.Nm passmenu
+.Nd dmenu interface for password-store (pass)
+.Sh SYNOPSIS
+.Nm passmenu
+.Op Fl hu
+.Op dmenu options
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a quick and easy interface for
+.Xr pass 1
+using
+.Xr dmenu 1
+.Ns . It reads all passwords from
+.Ev PASSWORD_STORE DIR
+(
+.Ns Pa ~/.password-store
+if unset) and displays them in dmenu. The selected password is
+copied to the clipboard.
+
+The following options are available:
+.Bl -tag -width Ds -compact
+.It Fl h
+Print usage
+.It Fl u
+Copy the username, not the password
+.It dmenu options
+.Nm
+accepts all options
+.Xr dmenu 1
+accepts and passes them to it.
+.El
+.Sh ENVIRONMENT
+.Pp
+The following environment variables affect
+.Nm
+:
+.Bl -tag -width Ds -compact
+.It Ev PASSWORD_STORE_DIR
+The location of the password-store
+.El
+.Sh EXIT STATUS
+.Nm
+returns 0 on success
+and
+1 on any error
+.Sh EXAMPLES
+Run
+.Nm
+with various options passed to dmenu:
+.Bd -literal -offset indent -compact
+passmenu -nb '#000' -nf '#FFF' -sb '#AAA' -sf '#000'
+.Be
+.Sh SEE ALSO
+.Xr pass 1
+.Xr dmenu 1
+.Sh HISTORY
+There is a popular script with the same name, however, that is a different
+implementation. As of 2019-05-20, said script is available at
+.Lk https://git.zx2c4.com/password-store/tree/contrib/dmenu/passmenu
+.Sh AUTHORS
+The
+.Nm
+script was written by
+.An Bertalan Z. Péter Aq Mt bertalanp99@bertalanp99.eu
+.Sh CAVEATS
+.Pp
+Beware that when copying passwords using the
+.Fl u
+option,
+.Nm
+actually just takes the second line of the password file and trims the string
+.Ql login:\
+out. Therefore passwords are expected to be stored in the form
+.Bd -literal -offset indent -compact
+my-highly-secure-password999
+login: my-username
+url: https://some-site.domain
+\&...
+.Ed
diff --git a/passmenu.sh b/passmenu.sh
new file mode 100755
index 0000000..9b6ad22
--- /dev/null
+++ b/passmenu.sh
@@ -0,0 +1,134 @@
+#!/bin/sh
+
+# !!!! UPDATE WITH ROFI GOODNESS
+
+###
+# passmenu - dmenu interface for password-store
+#
+# The popular, commonly used script for this purpose is available at
+# <https://git.zx2c4.com/password-store/tree/contrib/dmenu/passmenu>
+# (as of 2019-05-20).
+# However, that script has been written in bash. This is my own, pure sh
+# implementation. I believe it is slower and a lot less efficient. Nevertheless,
+# it just works(TM). It is also tailored to my own liking.
+#
+# The script requires the following binaries in PATH to work:
+# - pass (password-store, obviously)
+# - dmenu (also rather obvious)
+# - xsel (for the ability to copy the username only)
+#
+# The script has a manual included, but for the sake of redundancy, the options
+# are also listed below. It accepts all options dmenu accepts and uses them as
+# expected.
+#
+# SYNOPSIS: passmenu [-hu] [dmenu options]
+# -h, --help print usage
+# -u, --username copy the username, not the password
+#
+# bertalanp99@ 2019-05-20
+###
+
+#################
+### FUNCTIONS ###
+#################
+
+usage()
+{
+ printf 'usage: passmenu [-hu]'
+}
+
+
+#################
+### VARIABLES ###
+#################
+
+prefix=${PASSWORD_STORE_DIR-$HOME/.password-store/}
+
+
+##############
+### SCRIPT ###
+##############
+
+### CHECK FOR BINARIES IN PATH ###
+
+for binary in pass rofi xsel
+do
+ if ! command -v $binary >/dev/null 2>&1
+ then
+ echo "this script needs '$binary' in PATH to work"
+ exit 1
+ fi
+done
+
+### PARSE OPTIONS ###
+
+needuser=0
+dmenuoptions=
+while [ -n "$1" ]
+do
+ case $1 in
+ -b|-f|-i|-v)
+ dmenuoptions="$dmenuoptions $1"
+ ;;
+
+ -l|-m|-p|-fn|-nb|-nf|-sb|-sf|-w)
+ dmenuoptions="$dmenuoptions $1 $2"
+ shift
+ ;;
+
+ -c)
+ cli=1
+ ;;
+
+ -h)
+ usage
+ exit 0
+ ;;
+
+ -u)
+ needuser=1
+ ;;
+
+ *)
+ echo "unknown option -- $1"
+ usage
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+### MAIN ###
+
+
+if [ -n "$cli" ]; then
+ password="`find "$prefix" -name '*.gpg' \
+ | sed "s|$prefix\(.*\).gpg|\1|" \
+ | fzf`"
+ pass show "$password"
+ exit
+fi
+
+password="$(\
+ find "$prefix" -name '*.gpg' \
+ | sed "s|${prefix}\(.*\).gpg|\1|" \
+ | rofi -dmenu $dmenuoptions)"
+
+if [ $needuser -eq 0 ]
+then
+ pw="$(pass show "$password" 2>/dev/null \
+ | sed 1q \
+ | tr -d '\n')"
+ xdotool type --delay 4 "$pw"
+else
+ login="$(pass show "$password" 2>/dev/null \
+ | awk '/login:/{print $2}' \
+ | tr -d '\n')"
+ pw="$(pass show "$password" 2>/dev/null \
+ | sed 1q \
+ | tr -d '\n')"
+ xdotool type --delay 4 "$login"
+ xdotool type --delay 4 "\t"
+ xdotool type --delay 4 "$pass"
+ xdotool type --delay 4 " "
+fi