summaryrefslogtreecommitdiff
path: root/yoshi/process.py
diff options
context:
space:
mode:
authorChristian Cleberg <hello@cleberg.net>2024-11-06 23:23:27 -0600
committerChristian Cleberg <hello@cleberg.net>2024-11-06 23:23:27 -0600
commit6dde4dd0bc5e5f91f89587c75a30c9ef7a24494c (patch)
tree6cf4b78ddd63a4606e19fcad423ed2e19ad2a268 /yoshi/process.py
parentb5a5fadff88615c8da8a9feb80c86fd8adb238f5 (diff)
downloadyoshi-cli-6dde4dd0bc5e5f91f89587c75a30c9ef7a24494c.tar.gz
yoshi-cli-6dde4dd0bc5e5f91f89587c75a30c9ef7a24494c.tar.bz2
yoshi-cli-6dde4dd0bc5e5f91f89587c75a30c9ef7a24494c.zip
package as a cli app
Diffstat (limited to 'yoshi/process.py')
-rw-r--r--yoshi/process.py226
1 files changed, 226 insertions, 0 deletions
diff --git a/yoshi/process.py b/yoshi/process.py
new file mode 100644
index 0000000..155f9b0
--- /dev/null
+++ b/yoshi/process.py
@@ -0,0 +1,226 @@
+"""
+Password Vault Manager
+
+This script provides various functions for managing password vaults.
+It allows users to create, list, edit and delete accounts.
+
+The `Account` class represents an individual account, with attributes for
+the application name, username, password, and URL. The database module is used
+to interact with the SQLite database file (`vault.sqlite`) that stores the
+accounts data.
+
+Functions:
+ generate_characters(n): generates a list of random characters
+ shuffle_characters(characters): shuffles the characters to create a password
+ generate_passphrase(n, sep): generates an XKCD-style passphrase with n words and separator
+ list_accounts(): lists all saved accounts in the database
+ delete_account(uuid): deletes an account by its UUID
+ purge_accounts(): purges the entire database (irreversible)
+ create_account(): creates a new account by prompting user for details
+ edit_account(uuid, edit_parameter): edits an existing account's details
+
+Usage:
+ Run this script in your terminal to access these functions.
+"""
+
+from string import ascii_letters, punctuation, digits
+import random
+import uuid
+from prettytable import PrettyTable
+from yoshi.account import Account
+import yoshi.database as database
+
+
+def generate_characters(n: int) -> list:
+ """
+ Generates a list of n random characters from the set of ASCII letters,
+ punctuation and digits.
+
+ Args:
+ n (int): The number of characters to generate
+
+ Returns:
+ list: A list of n random characters
+ """
+ characters = []
+ password_format = ascii_letters + punctuation + digits
+ for _ in range(n):
+ characters.append(random.choice(password_format))
+ return characters
+
+
+def shuffle_characters(characters: list) -> str:
+ """
+ Shuffles the characters to create a password.
+
+ Args:
+ characters (list): The list of characters
+
+ Returns:
+ str: A string representation of the shuffled characters
+ """
+ random.shuffle(characters)
+ character_string = ''.join(characters)
+ return character_string
+
+
+def generate_passphrase(n: int, sep: str) -> str:
+ """
+ Generates an XKCD-style passphrase with n words and separator.
+
+ Args:
+ n (int): The number of words to include
+ sep (str): The separator symbol
+
+ Returns:
+ str: A string representation of the passphrase
+ """
+ phrases = []
+ lucky_number = random.choice(range(0, n))
+ for _ in range(n):
+ with open('wordlist.txt', 'r', encoding='utf-8') as file:
+ line = random.choice(file.readlines())
+ line = line.replace('\n', '')
+ if _ == lucky_number:
+ phrases.append(line.strip().capitalize() + str(_))
+ else:
+ phrases.append(line.strip().capitalize())
+ passphrase = sep.join(phrases)
+ return passphrase
+
+
+def list_accounts() -> None:
+ """
+ Lists all saved accounts in the database.
+
+ Returns:
+ None
+ """
+ accounts = database.find_accounts()
+ t = PrettyTable(['UUID', 'Application', 'Username', 'Password', 'URL'])
+ for account in accounts:
+ t.add_row([account[0], account[1], account[2], account[3], account[4]])
+ print(t)
+
+
+def delete_account(account_uuid: str) -> None:
+ """
+ Deletes an account by its UUID.
+
+ Args:
+ account_uuid (str): The UUID of the account to delete
+
+ Returns:
+ None
+ """
+ account_record = database.find_account(account_uuid)
+ account = Account(account_record[0][0],
+ account_record[0][1],
+ account_record[0][2],
+ account_record[0][3],
+ account_record[0][4])
+ if account.delete_account():
+ print('Account successfully deleted.')
+
+
+def purge_accounts() -> None:
+ """
+ Purges the entire database (irreversible).
+
+ Returns:
+ None
+ """
+ check = input(
+ '''Are you absolutely sure you want to delete your password vault?
+ This action is irreversible. (y/n): ''')
+ if check.lower() == 'y':
+ database.purge_table()
+ database.purge_database()
+ print('The password vault has been purged. You may now exit or create a new one.')
+
+
+def create_account() -> None:
+ """
+ Creates a new account by prompting user for details.
+
+ Returns:
+ None
+ """
+ application_string = input('Please enter a name for this account: ')
+ username_string = input('Please enter your username for this account: ')
+ url_string = input('(Optional) Please enter a URL for this account: ')
+
+ password_type = input(
+ '''Do you want a random character password (p), an XKCD-style passphrase
+(x), or a custom password (c)? (p|x|c): '''
+ )
+ if password_type not in ['p', 'x', 'c']:
+ print('Error: Invalid choice. Please choose p, x, or c.')
+ return
+
+ if password_type == 'x':
+ password_length = int(
+ input('Please enter number of words to include (min. 2): ')
+ )
+ if password_length < 3:
+ print('Error: Your passphrase length must be at least 3 words.')
+ return
+ password_separator = input(
+ 'Please enter your desired separator symbol (_,-, ~, etc.): '
+ )
+ password_string = generate_passphrase(password_length, password_separator)
+ elif password_type == 'p':
+ password_length = int(
+ input('Please enter your desired password length (min. 8): ')
+ )
+ if password_length < 8:
+ print('Error: Your password length must be at least 8 characters.')
+ return
+ password_characters = generate_characters(password_length)
+ password_string = shuffle_characters(password_characters)
+ else:
+ password_string = input('Please enter your desired password: ')
+
+ account = Account(str(uuid.uuid4()), application_string,
+ username_string, password_string, url_string)
+ account.save_account()
+ print('Account saved to the vault. Use `--list` to see all saved accounts.')
+
+
+
+def edit_account(account_uuid: str, edit_parameter: int) -> None:
+ """
+ Allow users to edit any account information except the UUID.
+
+ Args:
+ account_uuid (str): Unique identifier of the account.
+ edit_parameter (int): Parameter indicating which field to edit.
+ Valid values are 1 for application name, 2 for username,
+ 3 for password, and 4 for URL.
+ """
+ field_name, new_value = ''
+ if edit_parameter == 1:
+ field_name = 'application'
+ new_value = input('Please enter your desired Application name: ')
+ elif edit_parameter == 2:
+ field_name = 'username'
+ new_value = input('Please enter your desired username: ')
+ elif edit_parameter == 3:
+ field_name = 'password'
+ type_check = input(
+ 'Do you want a new random password or to enter a custom password? '
+ '(random/custom): ').lower()
+ if type_check == 'random':
+ password_length = int(input('Please enter your desired password length: '))
+ if password_length < 8:
+ print('Error: Your password length must be at least 8 characters.')
+ else:
+ password_characters = generate_characters(password_length)
+ new_value = shuffle_characters(password_characters)
+ else:
+ new_value = input('Please enter your desired password: ')
+ elif edit_parameter == 4:
+ field_name = 'url'
+ new_value = input('Please enter your desired URL: ')
+ database.update_account(field_name, new_value, account_uuid)
+ print('Account successfully updated.')