Advertisement
Guest User

Untitled

a guest
Apr 16th, 2019
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.76 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. """
  4. Insert login information using bitwarden cli and dmenu.
  5. """
  6.  
  7. import argparse
  8. import os
  9. import sys
  10. import enum
  11. import functools
  12. import subprocess
  13. import json
  14.  
  15. USAGE = """Suggested bindings similar to Uzbl's `formfiller` script:
  16. config.bind('<z><l>', 'spawn --userscript qute-bw')
  17. config.bind('<z><u><l>', 'spawn --userscript qute-bw --username-only')
  18. config.bind('<z><p><l>', 'spawn --userscript qute-bw --password-only')
  19. config.bind('<z><o><l>', 'spawn --userscript qute-bw --otp-only')
  20. """
  21.  
  22. argument_parser = argparse.ArgumentParser(
  23. description=__doc__,
  24. usage=USAGE)
  25. argument_parser.add_argument(
  26. 'url',
  27. nargs='?',
  28. default=os.getenv('QUTE_URL'))
  29. argument_parser.add_argument(
  30. '--no-insert-mode',
  31. '-n',
  32. dest='insert_mode',
  33. action='store_false',
  34. help="Don't automatically enter insert mode")
  35. group = argument_parser.add_mutually_exclusive_group()
  36. group.add_argument(
  37. '--username-only',
  38. '-u',
  39. action='store_true',
  40. help='Only insert username')
  41. group.add_argument(
  42. '--password-only',
  43. '-p',
  44. action='store_true',
  45. help='Only insert password')
  46. group.add_argument(
  47. '--otp-only',
  48. '-o',
  49. action='store_true',
  50. help='Only insert OTP code')
  51.  
  52. stderr = functools.partial(print, file=sys.stderr)
  53.  
  54.  
  55. class ExitCodes(enum.IntEnum):
  56. SUCCESS = 0
  57. FAILURE = 1
  58. # 1 is automatically used if Python throws an exception
  59. NO_CANDIDATES = 2
  60.  
  61.  
  62. def _run_bw(command):
  63. qute_config = os.environ.get('QUTE_CONFIG_DIR')
  64. with open(qute_config+"/bw.conf", "r") as f:
  65. conf = json.loads(f.read())
  66. args = [conf['executable'], '--session', conf['session_key']] + command
  67. process = subprocess.run(args, stdout=subprocess.PIPE)
  68. try:
  69. return json.loads(process.stdout)
  70. except json.JSONDecodeError:
  71. return process.stdout.decode().strip()
  72.  
  73.  
  74. def qute_command(command):
  75. with open(os.environ['QUTE_FIFO'], 'w') as fifo:
  76. fifo.write(command + '\n')
  77. fifo.flush()
  78.  
  79.  
  80. def find_candidates(domain):
  81. sites = _run_bw(['list', 'items', '--url', domain])
  82. return list(map(lambda x: f"{x['name']} | {x['id']}", sites))
  83.  
  84.  
  85. def dmenu(items):
  86. process = subprocess.run(
  87. ['dmenu', '-i', '-l', '32'],
  88. input='\n'.join(items).encode(),
  89. stdout=subprocess.PIPE)
  90. return process.stdout.decode().strip()
  91.  
  92.  
  93. def main(arguments):
  94. if not arguments.url:
  95. argument_parser.print_help()
  96. return ExitCodes.FAILURE
  97.  
  98. candidates = find_candidates(arguments.url)
  99. if not candidates:
  100. stderr(f'No condidates for URL {arguments.url} found!')
  101. return ExitCodes.NO_CANDIDATES
  102.  
  103. selection = None
  104. if len(candidates) == 1:
  105. selection = candidates.pop()
  106. else:
  107. selection = dmenu(candidates)
  108.  
  109. if not selection:
  110. return ExitCodes.SUCCESS
  111.  
  112. # Extract selection ID
  113. selection = selection.split('|')[-1].strip()
  114.  
  115. username = _run_bw(['get', 'username', selection])
  116. password = _run_bw(['get', 'password', selection])
  117. otp = _run_bw(['get', 'totp', selection])
  118. if otp == b'No TOTP available for this login.\n':
  119. otp = None
  120.  
  121. if arguments.username_only:
  122. qute_command(f'fake-key "{username}"')
  123. elif arguments.password_only:
  124. qute_command(f'fake-key "{password}"')
  125. elif arguments.otp_only:
  126. qute_command(f'fake-key "{otp}"')
  127. else:
  128. qute_command(f'fake-key "{username}"')
  129. qute_command('fake-key <Tab>')
  130. qute_command(f'fake-key "{password}"')
  131.  
  132. if arguments.insert_mode:
  133. qute_command('enter-mode insert')
  134.  
  135. return ExitCodes.SUCCESS
  136.  
  137.  
  138. if __name__ == '__main__':
  139. arguments = argument_parser.parse_args()
  140. sys.exit(main(arguments))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement