try: import base64 from tabulate import tabulate from pysqlcipher3 import dbapi2 as sc from pyotp import TOTP from math import log2 from password_strength import PasswordStats from getpass import getpass as gp from secrets import token_urlsafe from random import randint as rint from os import path except ModuleNotFoundError: print("You have not installed the required modules. Follow these steps to do so:\n\n1. Open the terminal (Linux/MacOS) or command prompt (Windows).\n2. Navigate to this directory and then to the files directory.\n3. Type 'pip install -r dependencies.txt'.\n4. Restart the program.\n\nIf you have followed all the steps correctly, keyvault will work on the next start.") exit() def database_enc(): global conn global cursor conn = sc.connect("database/keyvault.db") cursor = conn.cursor() if path.isfile("database/keyvault.db"): for _ in range(3): try: password = gp(prompt = "Enter master password: ") cursor.execute(f"PRAGMA key = {password}") cursor.execute(''' CREATE TABLE IF NOT EXISTS data ( id INTEGER PRIMARY KEY AUTOINCREMENT, service TEXT, username TEXT, email TEXT, password TEXT, website TEXT, category TEXT, notes TEXT, totp TEXT ) ''') passCorrect = True break except sc.DatabaseError: print("Incorrect password.\n") passCorrect = False if not passCorrect: print("You have entered a wrong password three times. Please restart the program to try again.") exit() else: print("You have not setup a master password yet. Please set one below.\n") while True: mp, mp2 = gp(prompt = "Enter a secure master password (hidden for privacy!): "), gp(prompt = "Please enter it again: ") if mp == mp2: if len(mp) < 8: print("\nThe master password you have set is too weak. Please set another one.") else: break else: print("Both of the passwords are different. Please enter the same password.") cursor.execute(f"PRAGMA key = {mp}") conn.commit() def gen(): userpass = input("Type 'u' to generate usernames or 'p' for passwords: ").lower() if userpass == 'u': with open("files/generation/wordlist.txt", "r") as f: words = f.readlines() word1, word2 = rint(0, 8874), rint(0, 8874) username = f"{words[word1][0:-1]}{words[word2][0:-1]}{rint(0, 100000)}" print(username) elif userpass == 'p': while True: try: length = int(input("Enter password length (above 8 only): ")) except ValueError: length = 16 print("Password length not specified. Defaulting to 16.") if length <= 7: print("The password is too short. Please enter it again.") else: pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~@#$%^&*()-_=+]}[{\"';:.>,= 0.33 and passstrength < 0.66: print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is of fair strength. Please consider changing it to a stronger one.\n") elif passstrength >= 0.66 and passstrength < 0.80: print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is strong.\n") elif passstrength >= 0.80 and passstrength < 0.9: print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is incredibly strong.\n") else: print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is practically uncrackable.\n") def add(): service = username = email = password = website = category = notes = totp = " " print("For any of these fields, don't type anything to make it an empty field.") service = input("Enter service: ") username = input("Enter username: ") email = input("Enter email: ") password = gp(prompt = "Enter password (hidden for privacy): ") website = input("Enter website: ") category = input("Enter category: ") notes = input("Enter notes: ") totp = input("Enter TOTP secret: ") data = [service, username, email, password, website, category, notes, totp] for _ in range(len(data)): if data[_] == "": data[_] = None cursor.execute("INSERT INTO data(service, username, email, password, website, category, notes, totp) VALUES(?, ?, ?, ?, ?, ?, ?, ?)", tuple(data)) conn.commit() def ls(cmd="SELECT * FROM data"): cursor.execute(cmd) data = list(cursor.fetchall()) if data == []: print("No results.") else: for _ in range(len(data)): data[_] = list(data[_]) if data[_][-1] != None: data[_].append(TOTP(str(data[_][-1])).now()) else: data[_].append(None) head = ["ID", "Service", "Username", "Email", "Password", "Website", "Category", "Notes", "TOTP Secret", "TOTP Code"] print(tabulate(data, headers = head, tablefmt = "grid")) return data def rm(): ls() delid = int(input("Enter the ID of the record you want to delete: ")) cursor.execute("DELETE FROM data WHERE id=?", (delid,)) conn.commit() def find(): print("The following search criteria are available: id, service, username, email, website, category") criterian = input("Enter your criterian here: ").lower() if criterian not in ['id', 'service', 'username', 'email', 'website', 'category']: print("You have selected an invalid criterian.") else: srchquery = input("Enter your search query: ") sqlquery = f"SELECT * FROM data WHERE {criterian}='{srchquery}'" ls(sqlquery) def edit(): print("The following edit criteria are available: id, service, username, email, password, website, category, notes, totp") criterian = input("Enter your criterian here: ").lower() if criterian not in ['id', 'service', 'username', 'email', 'password', 'website', 'category', 'notes', 'totp']: print("You have selected an invalid criterian.") else: idsearch = input("Enter the ID of the entry to edit: ") data = ls(f"SELECT * FROM data WHERE id={idsearch}") if data == []: print("This entry does not exist.") else: confirmation = input("Is this the correct entry? [y/n] > ").lower() if confirmation == 'y': newvalue = input("Enter the new value: ") cursor.execute(f"UPDATE data SET {criterian}='{newvalue}' WHERE id={idsearch}") else: print("You have cancelled the entry edit process.") database_enc() with open("files/strength/common-passwords.txt", "r") as f: common_passwords = f.read() print("\nkeyvault initialized.") print("keyvault is ready to use! Type 'help' for a list of commands.\n") while True: command = input("> ")[0:2].lower() if command[0] == 'h': print(""" Usage: add - add an entry ls - list entires edit - edit an entry find - open search wizard rm - remove entry gen - generate a password or username strength - check password strength help - display this message version - print current version quit - quit the program """) elif command[0] == 'f': find() elif command[0] == 'l': ls() elif command[0] == 'a': add() elif command[0] == 'r': rm() elif command == 'ed': edit() elif command[0] == 'v': print("keyvault: v1.0.6") elif command[0] == 'g': gen() elif command[0] == 's': strength() elif command[0] == 'q' or command == 'ex': print("Thank for you using keyvault!") exit()