From 2ac2bc83907e8c7c7a3f0e49982bf00fe84a4f8a Mon Sep 17 00:00:00 2001 From: oscux Date: Wed, 20 Mar 2024 18:48:55 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20manager.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 manager.py diff --git a/manager.py b/manager.py new file mode 100644 index 0000000..983d8e2 --- /dev/null +++ b/manager.py @@ -0,0 +1,105 @@ +import sys +import os +from getpass import getpass +from hashlib import md5, sha256 +from base64 import b64encode +from os.path import expanduser +import pyperclip +import nacl.secret + +def show_usage_error(error_message): + raise Exception(f"""Invalid usage: {error_message} + +Syntax: python3 manager.py + +Commands: + save + read + readv1 + auth + del + list""") + +def read_passwords_list(): + passwords_list_path = '.ps_list' + if not os.path.exists(passwords_list_path): + save_passwords_list([]) + with open(passwords_list_path, 'r') as file: + return file.read().splitlines() + +def save_passwords_list(passwords_list): + with open('.ps_list', 'w') as file: + file.writelines('\n'.join(passwords_list)) + +def append_to_passwords_list(new_entries): + current_list = read_passwords_list() + updated_list = current_list + new_entries + save_passwords_list(list(set(updated_list))) + +def decrypt_master_password(protect_pass=None): + master_pass_path = f'{expanduser("~")}/.master_pass' + with open(master_pass_path, 'rb') as file: + encrypted_data = file.read() + if not protect_pass: + protect_pass = getpass("Protect password: ") + protect_hash = sha256(protect_pass.encode('utf-8')).digest() + box = nacl.secret.SecretBox(protect_hash) + nonce = encrypted_data[:nacl.secret.SecretBox.NONCE_SIZE] + encrypted = encrypted_data[nacl.secret.SecretBox.NONCE_SIZE:] + return box.decrypt(encrypted, nonce) + +def process_command(args): + if len(args) < 2: + show_usage_error("No command provided.") + + command = args[1] + if command in ['save', 'del'] and len(args) < 3: + show_usage_error("Missing arguments for command.") + + if command == 'save': + entry_name = args[2] + comment = input("Enter comment for this password: ") + entry = f"{entry_name} – {comment}" if comment else entry_name + append_to_passwords_list([entry]) + print("Entry saved.") + elif command == 'auth': + master_pass = getpass("Master-password: ").encode('utf-8') + protect_pass = getpass("Protect password: ") + protect_hash = sha256(protect_pass.encode('utf-8')).digest() + box = nacl.secret.SecretBox(protect_hash) + encrypted = box.encrypt(master_pass) + with open(f'{expanduser("~")}/.master_pass', 'wb') as file: + file.write(encrypted) + print("Master-password saved.") + elif command == 'read': + master_pass = decrypt_master_password() + postfix = getpass("Password postfix: ") + hash_digest = sha256(master_pass + postfix.encode('utf-8')).digest() + password = b64encode(hash_digest).decode().replace('=', '.').replace('+', '-').replace('/', '_') + pyperclip.copy(password) + print("Password copied to clipboard.") + elif command == 'readv1': + master_pass = decrypt_master_password() + postfix = getpass("Password postfix: ") + hash_digest = md5(master_pass + postfix.encode('utf-8')).digest() + password = b64encode(hash_digest).decode().replace('=', '') + pyperclip.copy(password) + print("Password (v1) copied to clipboard.") + elif command == 'del': + entry_name = args[2] + updated_list = [entry for entry in read_passwords_list() if not entry.startswith(entry_name)] + save_passwords_list(updated_list) + print("Entry deleted.") + elif command == 'list': + print("Known passwords:") + for entry in read_passwords_list(): + print(entry) + else: + show_usage_error("Unknown command.") + +if __name__ == '__main__': + try: + process_command(sys.argv) + except Exception as e: + print(f"Error: {e}") + sys.exit(1) \ No newline at end of file