Improve compat with pass. Bump.

This commit is contained in:
Manuel Amador (Rudd-O) 2019-07-10 01:35:12 +00:00
parent 2eea0c9345
commit 13a5554eec
3 changed files with 87 additions and 28 deletions

View File

@ -23,9 +23,15 @@ usage = "\n".join([
" Retrieves the list of keys from the pass store.", " Retrieves the list of keys from the pass store.",
" <key>", " <key>",
" Retrieves a key from the pass store.", " Retrieves a key from the pass store.",
" get-or-generate [-n] <key>", " generate [-n] [-f] <key> [pass-length]",
" Retrieves a key from the pass store; creates the key", " Retrieves a key from the pass store; creates the key",
" with 32 characters length if it does not exist yet,", " with 25 characters length if it does not exist yet,",
" and returns the generated key on standard output.",
" The -n option excludes symbols from being used",
" during password generation.",
" get-or-generate [-n] <key> [pass-length]",
" Retrieves a key from the pass store; creates the key",
" with 25 characters length if it does not exist yet,",
" and returns the generated key on standard output.", " and returns the generated key on standard output.",
" The -n option excludes symbols from being used", " The -n option excludes symbols from being used",
" during password generation.", " during password generation.",
@ -93,18 +99,25 @@ else:
p.add_argument("key", help="name of the key to be removed", type=str) p.add_argument("key", help="name of the key to be removed", type=str)
p = _newcmd("get-or-generate", p = _newcmd("get-or-generate",
"retrieves a key from the store, generating one if it does not exist") "retrieves a key from the password store, generating one if it does not exist")
p.add_argument("key", help="name of the key to be retrieved / generated", type=str) p.add_argument("key", help="name of the key to be retrieved / generated", type=str)
p = _newcmd("generate",
"generates a key in the password store")
p.add_argument("key", help="name of the key to be generated", type=str)
p = _newcmd("insert", p = _newcmd("insert",
"inserts a new key into the pass store") "inserts a new key into the pass store")
p.add_argument("key", help="name of the key to be inserted", type=str) p.add_argument("key", help="name of the key to be inserted", type=str)
for p in ["get-or-generate"]: for p in ["get-or-generate", "generate"]:
_parsers[p].add_argument("pass_length", type=int, nargs='?',
help="number of characters in generated password",
default=25)
_parsers[p].add_argument("-n", "--no-symbols", action="store_true", _parsers[p].add_argument("-n", "--no-symbols", action="store_true",
help="no symbols in generated password", help="no symbols in generated password",
default=False) default=False)
for p in ["mv", "cp", "rm", "insert"]: for p in ["mv", "cp", "rm", "insert", "generate"]:
_parsers[p].add_argument("-f", "--force", action="store_true", _parsers[p].add_argument("-f", "--force", action="store_true",
help="force overwriting / removing passwords instead of prompting", help="force overwriting / removing passwords instead of prompting",
default=False) default=False)
@ -146,6 +159,11 @@ PASS_MANAGE = "ruddo.PassManage"
def send_args(rpc, *args, **kwargs): def send_args(rpc, *args, **kwargs):
cmd = ['/usr/lib/qubes/qrexec-client-vm', opts.dest_vm, rpc] cmd = ['/usr/lib/qubes/qrexec-client-vm', opts.dest_vm, rpc]
# print(cmd, file=sys.stderr) # print(cmd, file=sys.stderr)
return_stdout = kwargs.get("return_stdout", False)
if "return_stdout" in kwargs:
del kwargs["return_stdout"]
kwargs['stdout'] = subprocess.PIPE
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
for arg in args: for arg in args:
# print(arg, file=sys.stderr) # print(arg, file=sys.stderr)
@ -154,8 +172,13 @@ def send_args(rpc, *args, **kwargs):
else: else:
arg = base64.b64encode(arg) + b"\n" arg = base64.b64encode(arg) + b"\n"
p.stdin.write(arg) p.stdin.write(arg)
if return_stdout:
out, unused_err = p.communicate('')
p.stdin.close() p.stdin.close()
return p.wait() if return_stdout:
return p.wait(), out
else:
return p.wait()
def pass_read(*args, **kwargs): def pass_read(*args, **kwargs):
@ -191,17 +214,59 @@ elif opts.subcommand == "rm":
sys.exit(1) sys.exit(1)
sys.exit(pass_manage(opts.subcommand, opts.key)) sys.exit(pass_manage(opts.subcommand, opts.key))
elif opts.subcommand == "get-or-generate": elif opts.subcommand == "get-or-generate":
sys.exit(pass_manage(opts.subcommand, opts.key, str(int(opts.no_symbols)))) with open(os.devnull, "w") as null:
ret, stdout = pass_read("get", opts.key, return_stdout=True, stderr=null)
if ret == 8:
# Not there.
with open(os.devnull, "w") as null:
ret = pass_manage("generate", opts.key, str(int(opts.no_symbols)), str(int(opts.pass_length)), stdout=null)
if ret != 0:
sys.exit(ret)
sys.exit(pass_read("get", opts.key))
elif ret == 0:
# There.
sys.stdout.buffer.write(stdout)
sys.exit(ret)
else:
# Woops.
sys.exit(ret)
elif opts.subcommand == "generate":
doit = lambda: sys.exit(pass_manage(opts.subcommand, opts.key, str(int(opts.no_symbols)), str(int(opts.pass_length))))
with open(os.devnull, "w") as null:
ret = pass_read("get", opts.key, stdout=null, stderr=null)
if ret == 8:
# Not there.
doit()
elif ret == 0:
# There:
if not opts.force and sys.stdin.isatty():
sys.stderr.write("An entry already exists for %s. Overwrite it? [y/N] " % (opts.key,))
ans = sys.stdin.readline().strip()
if ans and ans[0] in "yY":
doit()
else:
sys.exit(1)
else:
doit()
else:
sys.exit(ret)
elif opts.subcommand == "insert": elif opts.subcommand == "insert":
if not opts.force and sys.stdin.isatty(): if not opts.force and sys.stdin.isatty():
with open(os.devnull, "w") as null: with open(os.devnull, "w") as null:
if pass_read("get", opts.key, stdout=null, stderr=null) == 0: ret = pass_read("get", opts.key, stdout=null, stderr=null)
if ret == 0:
# There. Confirm.
sys.stderr.write("An entry already exists for %s. Overwrite it? [y/N] " % (opts.key,)) sys.stderr.write("An entry already exists for %s. Overwrite it? [y/N] " % (opts.key,))
ans = sys.stdin.readline().strip() ans = sys.stdin.readline().strip()
if ans and ans[0] in "yY": if ans and ans[0] in "yY":
pass pass
else: else:
sys.exit(1) sys.exit(1)
elif ret == 8:
# Not there. Fall through.
pass
else:
sys.exit(ret)
if opts.multiline: if opts.multiline:
print("Enter contents of %s and press Ctrl+D when finished:\n" % (opts.key, ), file=sys.stderr) print("Enter contents of %s and press Ctrl+D when finished:\n" % (opts.key, ), file=sys.stderr)
contents = sys.stdin.buffer.read() contents = sys.stdin.buffer.read()

View File

@ -25,32 +25,26 @@ if [ "$cmd" == "init" ] ; then
echo "To back up your password store, back up the entire $HOSTNAME VM using Qubes backup." >&2 echo "To back up your password store, back up the entire $HOSTNAME VM using Qubes backup." >&2
echo "Key files to backup: $HOME/.password-store and $HOME/.gnupg2" >&2 echo "Key files to backup: $HOME/.password-store and $HOME/.gnupg2" >&2
elif [ "$cmd" == "get-or-generate" ] ; then elif [ "$cmd" == "generate" ] ; then
read -n 4096 entry read -n 4096 entry
read -n 4096 nosymbols read -n 4096 nosymbols
read -n 4096 numchars
entry=$(echo "$entry" | base64 -d) entry=$(echo "$entry" | base64 -d)
nosymbols=$(echo "$nosymbols" | base64 -d) nosymbols=$(echo "$nosymbols" | base64 -d)
numchars=$(echo "$numchars" | base64 -d)
ret=0 ; out=$(pass -- "$entry" 2>&1) || ret=$? logger -t ruddo.PassManage "creating password entry $entry"
if [ "$ret" == "1" ] && echo "$out" | grep -q "not in the password store" ; then ret=0
logger -t ruddo.PassManage "creating password entry $entry" if [ "$nosymbols" == "1" ] ; then
ret=0 pass generate -n -f -- "$entry" "$numchars" || ret=$?
if [ "$nosymbols" == "1" ] ; then else
out=$(pass generate -n -- "$entry" 32) || ret=$? pass generate -f -- "$entry" "$numchars" || ret=$?
else fi
out=$(pass generate -- "$entry" 32) || ret=$? if [ "$ret" != "0" ] ; then
fi logger -t ruddo.PassManage "Password generation failed: $out" >&2
if [ "$ret" == "1" ] ; then exit "$ret"
echo "Password generation failed: $out"
exit "$ret"
fi
elif [ "$ret" != "0" ] ; then
echo "$out" >&2
exit "$ret"
fi fi
logger -t ruddo.PassManage "requested password entry $entry"
exec pass -- "$entry"
elif [ "$cmd" == "insert" ] ; then elif [ "$cmd" == "insert" ] ; then

View File

@ -3,7 +3,7 @@
%define mybuildnumber %{?build_number}%{?!build_number:1} %define mybuildnumber %{?build_number}%{?!build_number:1}
Name: qubes-pass Name: qubes-pass
Version: 0.0.15 Version: 0.0.16
Release: %{mybuildnumber}%{?dist} Release: %{mybuildnumber}%{?dist}
Summary: Inter-VM pass password management for Qubes OS AppVMs and StandaloneVMs Summary: Inter-VM pass password management for Qubes OS AppVMs and StandaloneVMs
BuildArch: noarch BuildArch: noarch