Commit bdcd515c authored by R's avatar R
Browse files

dpass: version 0.1.2

parent e5d280f3
#!/usr/bin/env python3
"""
dpass is a wrapper around gopass for use with dmenu.
Try ``dpass -h`` for all the options.
"""
import sys
import argparse
import subprocess
import webbrowser
import time
__version__ = '0.1.2'
DMENUOPTS = ['-nb', '#93a1a1',
'-nf', '#073642',
'-sb', '#b58900',
'-sf', '#073642']
parser = argparse.ArgumentParser()
......@@ -14,7 +28,7 @@ parser.add_argument('-t', '--type',
parser.add_argument('-l', '--login',
action="store_true",
default=False,
help="Type a login (username, tab, password, enter)")
help="Type a login (username, tab, password)")
parser.add_argument('-u', '--url',
action="store_true",
default=False,
......@@ -22,6 +36,22 @@ parser.add_argument('-u', '--url',
parser.add_argument('-o', '--otp',
action='store_true',
help="Type the OTP value")
parser.add_argument('-i', '--user-id',
action='store_true',
help="Type the username")
parser.add_argument('-e', '--enter',
action='store_true',
help="Type enter after the sequence")
parser.add_argument('-d', '--delay',
default=0,
type=int,
help="Delay in ms before starting to type username and/or"
" password. Default: %(default)s.")
parser.add_argument('-k', '--key-delay',
default=60,
type=int,
help="Delay in ms between each keystroke when typing"
" username and/or password. Default %(default)s.")
args = parser.parse_args(sys.argv[1:])
......@@ -39,8 +69,24 @@ for line in str(rawentries, "utf-8").split("\n"):
entries.append(line)
# hint the purpose
prompt = 'to clipboard'
if args.type:
prompt = 'type password'
elif args.url:
prompt = 'open'
elif args.login:
prompt = 'login'
elif args.otp:
prompt = 'totp'
elif args.user_id:
prompt = 'user id'
# ask the user to select the entry
with subprocess.Popen(["dmenu", "-i"], stdout=subprocess.PIPE, stdin=subprocess.PIPE) as dmenu:
with subprocess.Popen(["dmenu", "-i", "-p", prompt] + DMENUOPTS,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE) as dmenu:
dmenu.stdin.write(bytes("\n".join(entries) + "\n", 'utf-8'))
dmenu.stdin.close()
selection = dmenu.stdout.read()
......@@ -51,70 +97,94 @@ if selection is None or selection not in entries:
sys.exit(-1)
# copy or type
if args.type:
with subprocess.Popen(["gopass", "show", "--force", "--password", selection], stdout=subprocess.PIPE) as gopass:
pwd = str(gopass.stdout.read(), 'utf-8')
with subprocess.Popen(["xdotool", "type", "--delay", "60", pwd]) as dotool:
pass
with subprocess.Popen(["xdotool", "key", "Return"]) as dotool:
def gopass(*params):
with subprocess.Popen(['gopass'] + list(params), stdout=subprocess.PIPE) as gp:
blob = str(gp.stdout.read(), 'utf-8')
return blob
def wait():
timeout = max(0, args.delay)
time.sleep(timeout/1000.0)
def xdo(*params):
with subprocess.Popen(["xdotool"] + list(params)) as dotool:
pass
elif args.url:
with subprocess.Popen(["gopass", "show", "--force", selection], stdout=subprocess.PIPE) as gopass:
blob = str(gopass.stdout.read(), 'utf-8')
if blob is None:
sys.exit(-1)
url = None
for line in blob.split("\n")[1:]:
if ':' in line and line.split(':', 1)[0].lower() in ['url']:
url = line.split(':', 1)[1].strip()
break
def xtype(*params):
timeout = str(max(0, args.key_delay))
xdo('type', '--delay', timeout, *params)
if url is not None:
webbrowser.open(url, new=2)
elif args.login:
with subprocess.Popen(["gopass", "show", "--force", selection], stdout=subprocess.PIPE) as gopass:
blob = str(gopass.stdout.read(), 'utf-8')
def enter():
if args.enter:
xdo("key", "Return")
def get_pass_entry(selection):
blob = gopass('show', '--force', selection)
if blob is None:
sys.exit(-1)
return None
pwd, rest = blob.split("\n", 1)
parts = blob.split("\n", 1)
pwd = parts[0]
if len(parts) == 1:
return pwd, None, None
rest = parts[1]
userid = None
url = None
for line in rest.split("\n"):
if ':' in line and line.split(':', 1)[0].lower() in ['user', 'username', 'login', 'uid']:
userid = line.split(':', 1)[1].strip()
break
if ':' not in line:
continue
k, v = line.split(':', 1)
k = k.lower()
v = v.strip()
if userid is None:
if userid is None and k in ['user', 'username', 'login', 'uid']:
userid = v
if url is None and k in ['url', 'website']:
url = v
return pwd, userid, url
if args.url:
_, _, url = get_pass_entry(selection)
if url is not None:
webbrowser.open(url, new=2)
elif args.login or args.user_id or args.type:
pwd, userid, _ = get_pass_entry(selection)
if args.user_id and userid is None:
sys.exit(-1)
if args.type and pwd is None:
sys.exit(-1)
with subprocess.Popen(["xdotool", "type", "--delay", "60", userid]) as dotool:
pass
with subprocess.Popen(["xdotool", "key", "Tab"]) as dotool:
pass
with subprocess.Popen(["xdotool", "type", "--delay", "60", pwd]) as dotool:
pass
with subprocess.Popen(["xdotool", "key", "Return"]) as dotool:
pass
wait()
if (args.login or args.user_id) and userid is not None:
xtype(userid)
if args.login:
xdo("key", "Tab")
if (args.login or args.type) and pwd is not None:
xtype(pwd)
enter()
elif args.otp:
with subprocess.Popen(["gopass", "otp", selection], stdout=subprocess.PIPE) as gopass:
blob = str(gopass.stdout.read(), 'utf-8')
blob = gopass('otp', selection)
if blob is None:
sys.exit(-1)
otp, _ = blob.split(' ', 1)
with subprocess.Popen(["xdotool", "type", "--delay", "60", otp]) as dotool:
pass
with subprocess.Popen(["xdotool", "key", "Return"]) as dotool:
pass
xtype(otp)
enter()
else:
with subprocess.Popen(["gopass", "--clip", selection], stdout=subprocess.PIPE) as gopass:
pass
gopass('--clip', selection)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment