-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
55b64e7
commit 9829ece
Showing
4 changed files
with
234 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import datetime | ||
import sys | ||
from collections import OrderedDict | ||
|
||
from peewee import * | ||
|
||
db = SqliteDatabase('passman.db') | ||
|
||
class BaseModel(Model): | ||
class Meta: | ||
database = db | ||
|
||
class User(BaseModel): | ||
username = CharField(max_length = 125, unique = True) | ||
password_hash = CharField(max_length = 255) | ||
|
||
class Password(BaseModel): | ||
user = ForeignKeyField(User, backref='passwords') | ||
application = CharField(max_length = 255) | ||
login = CharField(max_length = 255) | ||
password = CharField(max_length = 255) | ||
notes = TextField(null = False) | ||
modified_at = DateTimeField(default = datetime.datetime.now) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
#!/usr/bin/env python3 | ||
# don't forget : chmod +x passman.py | ||
|
||
import bcrypt | ||
from models import * | ||
from colorama import init | ||
from termcolor import colored, cprint | ||
|
||
init() | ||
|
||
line = "\n" + ('=' * 25) + "\n" | ||
current_user = None | ||
|
||
def initialize(): | ||
"""Create the database and tables if they don't already exist""" | ||
db.connect() | ||
db.create_tables([Password, User], safe = True) | ||
|
||
def check_users(): | ||
users = User.select() | ||
if not users.exists(): | ||
create_user() | ||
|
||
|
||
def create_user(): | ||
"""Create a new user""" | ||
cprint('Create a new user', 'magenta', attrs=['bold']) | ||
new_user = False | ||
while new_user == False: | ||
print(line) | ||
username = input(f"Enter a {colored('username', 'cyan')}: ") | ||
password = input(f"Enter a {colored('password', 'cyan')}: ") | ||
confirmation = input(f"Confirm {colored('password', 'cyan')}: ") | ||
|
||
errors = [] | ||
if username == "": | ||
errors.append('Missing username') | ||
if password == "": | ||
errors.append('Missing password') | ||
if confirmation == "": | ||
errors.append('Missing password confirmation') | ||
if password != confirmation: | ||
errors.append('Password and confirmation do not match') | ||
|
||
if print_errors(errors) == True: | ||
continue | ||
|
||
query = User.select().where(User.username == username) | ||
if query.exists(): | ||
print("Username unavailable. Please try again.") | ||
continue | ||
|
||
hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()) | ||
global current_user | ||
current_user = User.create( | ||
username = username, | ||
password_hash = hash | ||
) | ||
cprint("User created successfully!", 'green') | ||
new_user = True | ||
|
||
|
||
def login(): | ||
global current_user | ||
if not current_user: | ||
login = False | ||
else: | ||
login = True | ||
|
||
while login == False: | ||
print(line) | ||
entered_username = input("Please enter your user name: ") | ||
entered_password = input("Please enter your master password: ") | ||
|
||
query = User.select().where(User.username == entered_username) | ||
if not query.exists(): | ||
print("User '{}' not found".format(entered_username)) | ||
continue | ||
|
||
created_user = User.get(User.username == entered_username) | ||
hash = bcrypt.hashpw(entered_password.encode('utf-8'), created_user.password_hash.encode('utf-8')) | ||
|
||
if created_user.password_hash.encode('utf-8') == hash: | ||
current_user = created_user | ||
login = True | ||
else: | ||
print("Password not valid for user '{}'".format(entered_username)) | ||
continue | ||
|
||
def print_errors(errors): | ||
if len(errors) > 0: | ||
cprint("** Error - entry cannot be saved", 'red') | ||
for error in errors: | ||
cprint(f"** {error}", 'red') | ||
print(line) | ||
return True | ||
else: | ||
return False | ||
|
||
def menu_loop(): | ||
"""Show the menu""" | ||
choice = None | ||
|
||
while choice != 'q': | ||
print(line) | ||
print("Enter" + colored(" 'q' ", 'yellow') + "to quit.") | ||
for key, value in menu.items(): | ||
print(colored(key, 'magenta') + ") " + value.__doc__) | ||
|
||
choice = input(colored('Action', 'cyan') + ': ').lower().strip() | ||
|
||
if choice in menu: | ||
menu[choice]() | ||
|
||
def add_password(): | ||
"""Add a password""" | ||
print(line) | ||
|
||
application = input(f"Enter the {colored('application name', 'magenta')}: ") | ||
login = input(f"Enter the {colored('login name', 'magenta')} (email or username): ") | ||
password = input(f"Enter {colored('password', 'magenta')}: ") | ||
password_again = input(f"Confirm {colored('password', 'magenta')}: ") | ||
notes = input(f"(optional) Enter {colored('notes/ additional info', 'magenta')}: ") | ||
|
||
errors = [] | ||
if application == "": | ||
errors.append('Missing application') | ||
if login == "": | ||
errors.append('Missing login') | ||
if password == "": | ||
errors.append('Missing password') | ||
if password_again == "": | ||
errors.append('Missing password confirmation') | ||
if password != password_again: | ||
errors.append('Password and confirmation do not match') | ||
|
||
print_errors(errors) | ||
|
||
if not errors: | ||
if input(f"{colored('Save password?', 'cyan')} [Yn] ").lower() != 'n': | ||
global current_user | ||
Password.create( | ||
user = current_user, | ||
application = application, | ||
login = login, | ||
password = password, | ||
notes = notes | ||
) | ||
cprint("Password saved successfully!", 'green') | ||
|
||
def view_passwords(search_query = None): | ||
"""View all passwords""" | ||
print(line) | ||
|
||
global current_user | ||
passwords = Password.select().where(Password.user == current_user).order_by(Password.modified_at.desc()) | ||
if search_query: | ||
passwords = passwords.where(Password.application.contains(search_query)) | ||
|
||
if not passwords: | ||
cprint("No records found...", 'yellow') | ||
|
||
for password in passwords: | ||
modified_at = password.modified_at.strftime('%B %d, %Y') | ||
print(line) | ||
print(f"{colored('Application Name', 'yellow')}: {password.application}") | ||
print(f"{colored('Login Credentials', 'yellow')}: {password.login}") | ||
print(f"{colored('Password', 'yellow')}: {password.password}") | ||
print(f"{colored('Notes', 'yellow')}: {password.notes}") | ||
print(f"{colored('Last Modified', 'yellow')}: {modified_at}") | ||
print("\n") | ||
print(f"{colored('n', 'magenta')}) for next password") | ||
print(f"{colored('q', 'magenta')}) return to main menu") | ||
|
||
next_action = input(f"{colored('Action', 'cyan')}: [Nq] ").lower().strip() | ||
if next_action == 'q': | ||
break | ||
|
||
def search_passwords(): | ||
"""Search all passwords by application name""" | ||
print(line) | ||
query = input(f"{colored('Search', 'cyan')}: ").lower().strip() | ||
view_passwords(query) | ||
|
||
|
||
def delete_password(password): | ||
"""Delete a password""" | ||
|
||
menu = OrderedDict([ | ||
('a', add_password), | ||
('v', view_passwords), | ||
('s', search_passwords), | ||
('c', create_user) | ||
]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Passman is a super simple console-based password management application | ||
|
||
Installation: pip install passwordmanager | ||
Usage: python passman | ||
|
||
Source: https://github.com/seanpierce/passman |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from distutils.core import setup | ||
|
||
setup( | ||
name='passwordmanager', | ||
version='1.2.4', | ||
packages=['passman',], | ||
license='Creative Commons Attribution-Noncommercial-Share Alike license', | ||
long_description=open('readme.txt').read(), | ||
url='https://github.com/seanpierce/passman', | ||
author='Sean Pierce Sumler', | ||
) |