Advertisement
FocusedWolf

Python: Password Generator

Apr 3rd, 2022 (edited)
473
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.73 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. # Version 10
  4.  
  5. # POSTED ONLINE: https://pastebin.com/g10jVftx
  6.  
  7. # Windows: $ pip install pyperclip asciimatics
  8. #
  9. # Linux:   $ sudo pacman -S python-pyperclip
  10. #          $ sudo pacman -S wl-clipboard    <-- Pyperclip has issues with KDE + Wayland. Installing this seems to get it to work.
  11. #          $ yay -S python-asciimatics
  12. #
  13. #          NOTE: For Linux you also need to install a copy/paste mechanism if you don't have one.
  14. #                KDE has /bin/klipper installed by default. For other window managers try [$ sudo pacman -S xclip] or [$ sudo pacman -S xsel].
  15. #
  16. #          NOTE: If you get error "Cannot find '.setClipboardContents' in object /klipper at org.kde.klipper",
  17. #                its because klipper isn't running on startup. Try Start > klipper to see if the problem goes away.
  18. #
  19. #          NOTE: To display klipper in the taskbar, right click the ^ > Configure System Tray... > Entries > Clipboard: [Show when relevant].
  20.  
  21. import pyperclip
  22. from asciimatics.screen import Screen
  23. from asciimatics.event import KeyboardEvent
  24.  
  25. # -----
  26.  
  27. def draw_menu(screen, menuItems, selectedIndex, title, highlight):
  28.     # Clear screen.
  29.     clear(screen)
  30.  
  31.     # Draw title.
  32.     if title:
  33.         writeline(screen, title)
  34.  
  35.     # Draw menu items.
  36.     for i in range(len(menuItems)):
  37.         menuItem = menuItems[i]
  38.         if highlight in menuItem:
  39.             left,right = menuItem.split(highlight)
  40.             write(screen, f' {"●" if i == selectedIndex else "○"} {left}', Screen.COLOUR_GREEN if i == selectedIndex else Screen.COLOUR_CYAN)
  41.             write(screen, f'{highlight}', Screen.COLOUR_RED)
  42.             writeline(screen, f'{right}', Screen.COLOUR_GREEN if i == selectedIndex else Screen.COLOUR_CYAN)
  43.         else:
  44.             writeline(screen, f' {"●" if i == selectedIndex else "○"} {menuItem}', Screen.COLOUR_RED)
  45.  
  46.     # Draw usage information.
  47.     writeline(screen)
  48.     writeline(screen, ' Make → Space', Screen.COLOUR_YELLOW)
  49.     writeline(screen, ' Copy → Enter', Screen.COLOUR_YELLOW)
  50.     writeline(screen, ' Rise → Up', Screen.COLOUR_YELLOW)
  51.     writeline(screen, ' Fall → Down', Screen.COLOUR_YELLOW)
  52.     writeline(screen, ' Smol → Left', Screen.COLOUR_YELLOW)
  53.     writeline(screen, ' Swol → Right', Screen.COLOUR_YELLOW)
  54.     writeline(screen, ' Quit → Escape', Screen.COLOUR_YELLOW)
  55.  
  56.     # Draw screen.
  57.     screen.refresh()
  58.  
  59. # -----
  60.  
  61. row = 0
  62. col = 0
  63. def writeline(screen, text='', color=Screen.COLOUR_WHITE):
  64.     global row
  65.     global col
  66.     lines = text.split('\n')
  67.     for i, line in enumerate(lines):
  68.         screen.print_at(line, col, row, color)
  69.         row += 1
  70.         col = 0
  71.  
  72. def write(screen, text='', color=Screen.COLOUR_WHITE):
  73.     global row
  74.     global col
  75.     lines = text.split('\n')
  76.     for i, line in enumerate(lines):
  77.         screen.print_at(line, col, row, color)
  78.         if i < len(lines) - 1:
  79.             row += 1
  80.             col = 0
  81.         else:
  82.             col += len(line)
  83.  
  84. def clear(screen):
  85.     global row
  86.     global col
  87.     row = 0
  88.     col = 0
  89.     screen.clear()
  90.  
  91. # -----
  92.  
  93. import string
  94.  
  95. # Character groups to be used in the password.
  96. CHARACTER_GROUPS = [
  97.     string.ascii_lowercase,
  98.     string.ascii_uppercase,
  99.     string.digits,
  100.     string.punctuation,
  101. ]
  102.  
  103. TIMESTAMP_DIVIDER = '_'
  104.  
  105. from datetime import datetime
  106. import secrets
  107. def generate_timestamped_passwords(password_length, count=5):
  108.     dt = datetime.now()
  109.     short_time_stamp = dt.strftime('%y%m%d')
  110.     password_characters = ''.join(CHARACTER_GROUPS)
  111.     password_characters = password_characters.replace(TIMESTAMP_DIVIDER, '')
  112.  
  113.     passwords = []
  114.     retries = 100
  115.     for _ in range(count):
  116.         for attempt in range(retries):
  117.             # SOURCE: https://docs.python.org/3/library/secrets.html
  118.             password = ''.join(secrets.choice(password_characters) for _ in range(password_length))
  119.             password = shuffle(short_time_stamp, password, TIMESTAMP_DIVIDER)
  120.             if validate_password(password):
  121.                 passwords.append(password)
  122.                 break
  123.         else:
  124.             passwords.append(f'ERROR: Failed to generate a valid password after {retries} attempts.')
  125.  
  126.     large_time_stamp = f' Created: {dt.strftime("%Y-%m-%d %H:%M:%S")}\n'
  127.     large_time_stamp += f' Length: {password_length}\n'
  128.     return passwords, large_time_stamp, short_time_stamp
  129.  
  130. # -----
  131.  
  132. MIN_CHARACTERS_PER_GROUP = 2
  133. def validate_password(password):
  134.     for group in CHARACTER_GROUPS:
  135.         if sum(char in group for char in password) < MIN_CHARACTERS_PER_GROUP:
  136.             return False
  137.     return True
  138.  
  139. # -----
  140.  
  141. # Insert a word into a sentence randomly.
  142. def shuffle(word, sentence, divider = ' '):
  143.     max_word_index = len(sentence) - len(word)
  144.  
  145.     # Generate a random integer in the range [0, n).
  146.     random_index = secrets.randbelow(max_word_index + 1)
  147.  
  148.     # Prevent sentences from starting/ending with a word divider.
  149.     if random_index == 1:
  150.         random_index = 0 # Push word left one position.
  151.     elif random_index == max_word_index - 1:
  152.         random_index = max_word_index # Push word right one position.
  153.  
  154.     # Insert the word into the sentence.
  155.     sentence = sentence[:random_index] + word + sentence[random_index + len(word):]
  156.  
  157.     # Insert word dividers.
  158.     sentence = list(sentence)
  159.     left_index = random_index - 1
  160.     right_index = random_index + len(word)
  161.     if left_index >= 0:
  162.         sentence[left_index] = divider
  163.     if right_index < len(sentence):
  164.         sentence[right_index] = divider
  165.     return ''.join(sentence)
  166.  
  167. # -----
  168.  
  169. def wait_for_any_keypress(screen):
  170.     writeline(screen, ' Press any key to continue . . . ')
  171.     screen.refresh()
  172.  
  173.     # Wait for user keyboard input indefinitely.
  174.     while True:
  175.         screen.wait_for_input(5) # Sleep for this many seconds while waiting for input. This prevents 100% CPU usage from the loop.
  176.         ev = screen.get_event()
  177.         if isinstance(ev, KeyboardEvent):
  178.             break
  179.  
  180. # -----
  181.  
  182. MIN_PASSWORD_LENGTH = 13
  183.  
  184. def main(screen):
  185.     password_length = 32
  186.     menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  187.     selectedIndex = 0
  188.  
  189.     draw_menu(screen, menuItems, selectedIndex, large_time_stamp, short_time_stamp) # Initial drawing.
  190.  
  191.     while True:
  192.         # Get keyboard input.
  193.         screen.wait_for_input(5) # Sleep for this many seconds while waiting for input. This prevents 100% CPU usage from the loop.
  194.         ev = screen.get_event()
  195.         if not isinstance(ev, KeyboardEvent):
  196.             continue
  197.  
  198.         # If Escape key is pressed.
  199.         elif ev.key_code == -1:
  200.             break
  201.  
  202.         # If Space key is pressed.
  203.         elif ev.key_code == ord(' '):
  204.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  205.  
  206.         # If Up key is pressed.
  207.         elif ev.key_code == Screen.KEY_UP:
  208.             # Loop around backwards.
  209.             selectedIndex = (selectedIndex - 1 + len(menuItems)) % len(menuItems)
  210.  
  211.         # If Down key is pressed.
  212.         elif ev.key_code == Screen.KEY_DOWN:
  213.             # Loop around forwards.
  214.             selectedIndex = (selectedIndex + 1) % len(menuItems)
  215.  
  216.         # If Left key is pressed.
  217.         elif ev.key_code == Screen.KEY_LEFT:
  218.             # Reduce length of passwords.
  219.             password_length = max(MIN_PASSWORD_LENGTH, password_length - 1)
  220.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  221.  
  222.         # If Right key is pressed.
  223.         elif ev.key_code == Screen.KEY_RIGHT:
  224.             # Increase length of passwords.
  225.             password_length = password_length + 1
  226.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  227.  
  228.         # If Enter key is pressed.
  229.         # NOTE: On Windows the enter key appears to be \r, and on Linux its \n.
  230.         elif ev.key_code == ord('\r') or ev.key_code == ord('\n'):
  231.             pyperclip.copy(menuItems[selectedIndex])
  232.             writeline(screen, f"\n Copied {menuItems[selectedIndex]} to clipboard.\n")
  233.             wait_for_any_keypress(screen)
  234.  
  235.         # Else an unexpected key is pressed.
  236.         #  else:
  237.         #      try:
  238.         #          writeline(screen, "\n The pressed key '{}' {} is not associated with a menu function.\n".format(chr(ev.key_code), ev.key_code))
  239.         #      except ValueError:
  240.         #          writeline(screen, "\n The pressed key {} is not associated with a menu function.\n".format(ev.key_code))
  241.         #      wait_for_any_keypress(screen)
  242.  
  243.         draw_menu(screen, menuItems, selectedIndex, large_time_stamp, short_time_stamp)
  244.  
  245. if __name__ == '__main__':
  246.     Screen.wrapper(main)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement