Advertisement
FocusedWolf

Python: Password Generator

Apr 3rd, 2022 (edited)
541
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.04 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. # Version 23
  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, ' Zoom → Ctrl+/-', Screen.COLOUR_YELLOW)
  55.     writeline(screen, ' Quit → Esc', Screen.COLOUR_YELLOW)
  56.  
  57.     # Draw screen.
  58.     screen.refresh()
  59.  
  60. # -----
  61.  
  62. row = 0
  63. col = 0
  64. def writeline(screen, text='', color=Screen.COLOUR_WHITE):
  65.     global row
  66.     global col
  67.     lines = text.split('\n')
  68.     for i, line in enumerate(lines):
  69.         screen.print_at(line, col, row, color)
  70.         row += 1
  71.         col = 0
  72.  
  73. def write(screen, text='', color=Screen.COLOUR_WHITE):
  74.     global row
  75.     global col
  76.     lines = text.split('\n')
  77.     for i, line in enumerate(lines):
  78.         screen.print_at(line, col, row, color)
  79.         if i < len(lines) - 1:
  80.             row += 1
  81.             col = 0
  82.         else:
  83.             col += len(line)
  84.  
  85. def clear(screen):
  86.     global row
  87.     global col
  88.     row = 0
  89.     col = 0
  90.     screen.clear()
  91.  
  92. # -----
  93.  
  94. import string
  95.  
  96. # Character groups to be used in the password.
  97. CHARACTER_GROUPS = [
  98.     string.ascii_lowercase,
  99.     string.ascii_uppercase,
  100.     string.digits,
  101.     string.punctuation,
  102.     #'!@#$%^&*()', # PayPal allowed punctuation characters.
  103. ]
  104.  
  105. PASSWORD_CHARACTERS = ''.join(CHARACTER_GROUPS)
  106.  
  107. # Remove unwanted characters.
  108. removal_table = str.maketrans('', '', r'|\\/`\'\"')
  109. PASSWORD_CHARACTERS = PASSWORD_CHARACTERS.translate(removal_table)
  110.  
  111. # Remove timestamp divider characters so they can be uniquely added to the password around the timestamp.
  112. TIMESTAMP_DIVIDER_LEFT = '('
  113. TIMESTAMP_DIVIDER_RIGHT = ')'
  114. PASSWORD_CHARACTERS = PASSWORD_CHARACTERS.replace(TIMESTAMP_DIVIDER_LEFT, '').replace(TIMESTAMP_DIVIDER_RIGHT, '')
  115.  
  116. from datetime import datetime
  117. import secrets
  118. def generate_timestamped_passwords(password_length, count=5):
  119.     dt = datetime.now()
  120.     short_time_stamp = f"{TIMESTAMP_DIVIDER_LEFT}{dt.strftime('%y%m%d')}{TIMESTAMP_DIVIDER_RIGHT}"
  121.     short_time_stamp_len = len(short_time_stamp)
  122.     passwords = []
  123.     retries = 100000
  124.     for _ in range(count):
  125.         for attempt in range(retries):
  126.             # SOURCE: https://docs.python.org/3/library/secrets.html
  127.             password = ''.join(secrets.choice(PASSWORD_CHARACTERS) for _ in range(password_length - short_time_stamp_len))
  128.  
  129.             # If the password has repeating characters.
  130.             # NOTE: The non-timestamped password is tested because the timestamp might fail the unique-segments test depending on what day it is.
  131.             if not has_unique_segments(password):
  132.                 continue
  133.  
  134.             # If the password uses characters from all categories.
  135.             if has_representative_characters(password):
  136.                 timestamped_password = shuffle(password, short_time_stamp)
  137.                 passwords.append(timestamped_password)
  138.                 break
  139.         else:
  140.             passwords.append(f'ERROR: Failed to generate a valid password after {retries} attempts.')
  141.  
  142.     large_time_stamp = f' Created: {dt.strftime("%Y-%m-%d %H:%M:%S")}\n'
  143.     large_time_stamp += f' Length: {password_length}\n'
  144.     return passwords, large_time_stamp, short_time_stamp
  145.  
  146. # -----
  147.  
  148. def has_representative_characters(s):
  149.     min_characters_per_group = min(4, len(s) // len(CHARACTER_GROUPS))
  150.     for group in CHARACTER_GROUPS:
  151.         if sum(char in group for char in s) < min_characters_per_group:
  152.             return False
  153.     return True
  154.  
  155. def has_unique_segments(s):
  156.     segment_length = 2 if len(s) > 80 else 10
  157.     for i in range(0, len(s), segment_length):
  158.         segment = s[i:i + segment_length]
  159.         if len(set(segment)) != len(segment):
  160.             return False
  161.     return True
  162.  
  163. # -----
  164.  
  165. # Insert a word into a sentence randomly.
  166. def shuffle(sentence, word):
  167.     max_word_index = len(sentence)
  168.  
  169.     # Generate a random integer in the range [0, n).
  170.     random_index = secrets.randbelow(max_word_index + 1)
  171.  
  172.     # Insert the word into the sentence.
  173.     sentence = sentence[:random_index] + word + sentence[random_index:]
  174.     return sentence
  175.  
  176. # -----
  177.  
  178. def wait_for_enter_keypress(screen):
  179.     writeline(screen, ' Press ENTER to continue . . . ')
  180.     screen.refresh()
  181.  
  182.     while True:
  183.         # Get keyboard input.
  184.         screen.wait_for_input(5) # Sleep for this many seconds while waiting for input to prevent 100% CPU usage from the loop.
  185.         ev = screen.get_event()
  186.         if not isinstance(ev, KeyboardEvent):
  187.             continue
  188.  
  189.         # If Enter key is pressed.
  190.         # NOTE: On Windows the enter key appears to be \r, and on Linux its \n.
  191.         if ev.key_code == ord('\r') or ev.key_code == ord('\n'):
  192.             break
  193.  
  194. def wait_for_any_keypress(screen):
  195.     writeline(screen, ' Press any key to continue . . . ')
  196.     screen.refresh()
  197.  
  198.     while True:
  199.         # Get keyboard input.
  200.         screen.wait_for_input(5) # Sleep for this many seconds while waiting for input to prevent 100% CPU usage from the loop.
  201.         ev = screen.get_event()
  202.         if isinstance(ev, KeyboardEvent):
  203.             break
  204.  
  205. # -----
  206.  
  207. MIN_PASSWORD_LENGTH = 12 # 6 numbers (timestamp) + 2 uppercase letters + 2 lowercase letters + 2 punctuation (timestamp-dividers).
  208.  
  209. def main(screen):
  210.     password_length = 32
  211.     menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  212.     selectedIndex = 0
  213.  
  214.     draw_menu(screen, menuItems, selectedIndex, large_time_stamp, short_time_stamp) # Initial drawing.
  215.  
  216.     while True:
  217.         # Get keyboard input.
  218.         screen.wait_for_input(5) # Sleep for this many seconds while waiting for input to prevent 100% CPU usage from the loop.
  219.         ev = screen.get_event()
  220.         if not isinstance(ev, KeyboardEvent):
  221.             continue
  222.  
  223.         # If Escape key is pressed.
  224.         elif ev.key_code == -1:
  225.             break
  226.  
  227.         # If Space key is pressed.
  228.         elif ev.key_code == ord(' '):
  229.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  230.  
  231.         # If Up key is pressed.
  232.         elif ev.key_code == Screen.KEY_UP:
  233.             # Loop around backwards.
  234.             selectedIndex = (selectedIndex - 1 + len(menuItems)) % len(menuItems)
  235.  
  236.         # If Down key is pressed.
  237.         elif ev.key_code == Screen.KEY_DOWN:
  238.             # Loop around forwards.
  239.             selectedIndex = (selectedIndex + 1) % len(menuItems)
  240.  
  241.         # If Left key is pressed.
  242.         elif ev.key_code == Screen.KEY_LEFT:
  243.             # Reduce length of passwords.
  244.             password_length = max(MIN_PASSWORD_LENGTH, password_length - 1)
  245.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  246.  
  247.         # If Right key is pressed.
  248.         elif ev.key_code == Screen.KEY_RIGHT:
  249.             # Increase length of passwords.
  250.             password_length = password_length + 1
  251.             menuItems, large_time_stamp, short_time_stamp = generate_timestamped_passwords(password_length)
  252.  
  253.         # If Enter key is pressed.
  254.         # NOTE: On Windows the enter key appears to be \r, and on Linux its \n.
  255.         elif ev.key_code == ord('\r') or ev.key_code == ord('\n'):
  256.             pyperclip.copy(menuItems[selectedIndex])
  257.             writeline(screen, f"\n Copied {menuItems[selectedIndex]} to clipboard.\n")
  258.             wait_for_enter_keypress(screen)
  259.  
  260.         # Else an unexpected key is pressed.
  261.         #  else:
  262.         #      try:
  263.         #          writeline(screen, "\n The pressed key '{}' {} is not associated with a menu function.\n".format(chr(ev.key_code), ev.key_code))
  264.         #      except ValueError:
  265.         #          writeline(screen, "\n The pressed key {} is not associated with a menu function.\n".format(ev.key_code))
  266.         #      wait_for_any_keypress(screen)
  267.  
  268.         draw_menu(screen, menuItems, selectedIndex, large_time_stamp, short_time_stamp)
  269.  
  270. if __name__ == '__main__':
  271.     Screen.wrapper(main)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement