Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python3
- """
- Insert login information using bitwarden cli and dmenu.
- """
- import argparse
- import os
- import sys
- import enum
- import functools
- import subprocess
- import json
- USAGE = """Suggested bindings similar to Uzbl's `formfiller` script:
- config.bind('<z><l>', 'spawn --userscript qute-bw')
- config.bind('<z><u><l>', 'spawn --userscript qute-bw --username-only')
- config.bind('<z><p><l>', 'spawn --userscript qute-bw --password-only')
- config.bind('<z><o><l>', 'spawn --userscript qute-bw --otp-only')
- """
- argument_parser = argparse.ArgumentParser(
- description=__doc__,
- usage=USAGE)
- argument_parser.add_argument(
- 'url',
- nargs='?',
- default=os.getenv('QUTE_URL'))
- argument_parser.add_argument(
- '--no-insert-mode',
- '-n',
- dest='insert_mode',
- action='store_false',
- help="Don't automatically enter insert mode")
- group = argument_parser.add_mutually_exclusive_group()
- group.add_argument(
- '--username-only',
- '-u',
- action='store_true',
- help='Only insert username')
- group.add_argument(
- '--password-only',
- '-p',
- action='store_true',
- help='Only insert password')
- group.add_argument(
- '--otp-only',
- '-o',
- action='store_true',
- help='Only insert OTP code')
- stderr = functools.partial(print, file=sys.stderr)
- class ExitCodes(enum.IntEnum):
- SUCCESS = 0
- FAILURE = 1
- # 1 is automatically used if Python throws an exception
- NO_CANDIDATES = 2
- def _run_bw(command):
- qute_config = os.environ.get('QUTE_CONFIG_DIR')
- with open(qute_config+"/bw.conf", "r") as f:
- conf = json.loads(f.read())
- args = [conf['executable'], '--session', conf['session_key']] + command
- process = subprocess.run(args, stdout=subprocess.PIPE)
- try:
- return json.loads(process.stdout)
- except json.JSONDecodeError:
- return process.stdout.decode().strip()
- def qute_command(command):
- with open(os.environ['QUTE_FIFO'], 'w') as fifo:
- fifo.write(command + '\n')
- fifo.flush()
- def find_candidates(domain):
- sites = _run_bw(['list', 'items', '--url', domain])
- return list(map(lambda x: f"{x['name']} | {x['id']}", sites))
- def dmenu(items):
- process = subprocess.run(
- ['dmenu', '-i', '-l', '32'],
- input='\n'.join(items).encode(),
- stdout=subprocess.PIPE)
- return process.stdout.decode().strip()
- def main(arguments):
- if not arguments.url:
- argument_parser.print_help()
- return ExitCodes.FAILURE
- candidates = find_candidates(arguments.url)
- if not candidates:
- stderr(f'No condidates for URL {arguments.url} found!')
- return ExitCodes.NO_CANDIDATES
- selection = None
- if len(candidates) == 1:
- selection = candidates.pop()
- else:
- selection = dmenu(candidates)
- if not selection:
- return ExitCodes.SUCCESS
- # Extract selection ID
- selection = selection.split('|')[-1].strip()
- username = _run_bw(['get', 'username', selection])
- password = _run_bw(['get', 'password', selection])
- otp = _run_bw(['get', 'totp', selection])
- if otp == b'No TOTP available for this login.\n':
- otp = None
- if arguments.username_only:
- qute_command(f'fake-key "{username}"')
- elif arguments.password_only:
- qute_command(f'fake-key "{password}"')
- elif arguments.otp_only:
- qute_command(f'fake-key "{otp}"')
- else:
- qute_command(f'fake-key "{username}"')
- qute_command('fake-key <Tab>')
- qute_command(f'fake-key "{password}"')
- if arguments.insert_mode:
- qute_command('enter-mode insert')
- return ExitCodes.SUCCESS
- if __name__ == '__main__':
- arguments = argument_parser.parse_args()
- sys.exit(main(arguments))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement