## ------------------------------------------------------------------------------------------------------------------------------ import re import sqlite3 #import mysqldb import sys import getpass try: conn = sqlite3.connect('userpass.db') except: print ("Cannot Find Any DB") exit() c = conn.cursor() ##### NOTE ##### First Time Users Uncomment the next two lines, until I make a feature rich installer #c.execute('''CREATE TABLE if not exists userpass(user text, pass text)''') #c.execute('''CREATE TABLE if not exixts p_history(user text, pass text)''') ### NOTE (Sankrant): ## This is my first time working with a structured database, I still do not know the left join correctly. So here you have it, ## two redundant tables to solve the triple password problem. A better design would be to make a primary key linked with the user ## on the first table, and use that key instead ## This is also a nightmare in security practice according to some database guys ## I should have created another secure storage for passwords doing some magic fu linking. Will come back to it later ## TODO (Sankrant): maybe hide the password entry by **** ## ------------------------------------------------------------------------------------------------------------------------------- def add_user(): username = input("Please Enter Username: ") if user_exists(username) == 1: print ("User Already Exists") exit() if check_user(username) == -1: print("Wrong Format: Please check formating by typing help as argument") exit() try: c.execute("INSERT INTO userpass VALUES (?, '')", (username,)) print ("User Added") except: print("The database query did not work") comDB() ## Sometimes Regex is too complex to put your head around ## Good old C style coding def issym(ch): if (ch == '!' or ch == '@' or ch == '#' or ch == '$' or ch == '%' or ch == '^' or ch == '&' or ch == '*' or ch == '(' or ch == ')' or ch == '-' or ch == '=' or ch == '+' or ch == '[' or ch == ']' or ch == '{' or ch == '}' or ch == '<' or ch == '>' or ch == '.' or ch == '?' or ch == ':' or ch == '|' or ch == '\\' or ch == '/' or ch == '`' or ch == '~'): return True; else: return False def check_7(password): for ind,ch in enumerate(password[:-2]): if ch.isupper() and password[ind+1].isupper() and password[ind+2].isupper(): return -1 elif ch.islower() and password[ind+1].islower() and password[ind+2].islower(): return -2 elif ch.isdigit() and password[ind+1].isdigit() and password[ind+2].isdigit(): return -3 elif issym(ch) and issym(password[ind+1]) and issym(password[ind+2]): return -4 return 0 def add_pass(username): password = input("Enter Password: ") check_password_count(username, password) if pass_check(password) == -1: print ("Follow the Password Rules") exit() elif pass_check(password) == 0: password_re = input("Retype Password: ") if (password == password_re): try: c.execute("INSERT INTO p_history VALUES (?, ?)", (username, password)) c.execute("UPDATE userpass SET pass = ? WHERE user = ?", (password, username)) except: print("Cant Connect to DB") exit() comDB() print ("Password Added for User") else: print ("The passwords do not match") exit() def CLIHelp(): print ( ''' Usage : python zdbdemo.py [option] [arg] Options -------- useradd : Prompts for adding a Username to the database with an empty password passwd : Add a Strong Password and take Username as an argument help : Display help ''' ) def Help(): print(''' User Rules ---------- A) To create new user : program_name useradd If the user does not exist, it will create a user and then prompt for a password for the user ( the password complexity is defined below ). This user will be stored in a DB or Flat file . If the username exists, it will fail letting the user know that the user already exists. The username can contain only _ or . As special character and nothing else . The username should not be greater than 10 characters. The username should not start with a number . B) To change password : program_name passwd $username The password check will be as below : The password length should be more than 8 characters. The password length should be less than 15 characters. The password should have atleast one [a-z] ( class 1) The password should have atleast one [0-9] ( class 2) The password should have at least one special character ( class 3 ) The password should not have characters /, ~, ` . One cannot have more than two same class characters adjacent to each other . One cannot use the same password which he/she has used in the past three times . Which means you will have to store the username and corresponding password either in some DB or you can even use a flat file and maintain a history of 3 for each user . The password should be entered twice and matched . ''') ## HELPER FUNCTIONS ## ---------------------------------------------------------------------------------------------------------------------------------- def purgeOldTable(): #if __counterCheck__() == 1: c.execute("DELETE FROM p_history") def pass_exists(username, password): c.execute("Select count(pass) from p_history where user=? and pass=?", (username, password)) asdf = c.fetchone()[0] c.execute("Select count(pass) from p_history where user=?", (username, )) ## TODO(Sankrant): Checking this stuff without pdb is frustating, do some debug ## TODO(Sankrant): Encapsulate all of this in clean functions qwer = c.fetchone()[0] if (qwer >= 3): purgeOldTable() if (asdf >= 1): return 1 else: return 0 def username_exists(password): try: fetch2 = c.execute("select user from p_history where pass=?", (pass_exists(username, password))).fetchone()[0] return fetch2 except: return 0 def user_exists(username): try: c.execute('''SELECT user FROM userpass WHERE user=?''', (username,)) except: print("Can not execute query") exit() exists = c.fetchall() if exists: return 1 def pass_check(password): ## TODO (Sankrant): Regular Expressions can be executed in a more elegant manner????? if (len(password) < 8 and len(password) > 15): flag = -1 elif not re.search("[a-z]", password): flag = -1 elif not re.search("[A-Z]", password): flag = -1 elif not re.search("[0-9]", password): flag = -1 elif not re.search("[_@$!#$%^&*()\\\]", password): flag = -1 elif re.search("[/~`]", password): flag = -1 elif check_7(password) != 0: flag = -1 else: flag = 0 return flag def check_user(username): if (len(username) > 10): flag = -1 elif re.search("[_.]", username): flag = -1 else: flag = 1 return flag def check_password_count(username, password): if pass_exists(username, password) == 1: print("Please Enter Another Password as this has been used before") exit() def comDB(): conn.commit() def do_nothing(): return ## ------------------------------------------------------------------------------------------------------------------------------------------- ## MAIN ## DONE (Sankrant): It is trivial to do the entry point function now, I might do it before the final show def main(): if(sys.argv[0] == "zdbdemo.py"): CLIHelp() if(sys.argv[1] == "useradd"): add_user() elif(sys.argv[1] == "useradd" and sys.argv[2] == "-p"): add_user() add_pass(username) elif(sys.argv[1] == "passwd" and sys.argv[2]): if (user_exists(sys.argv[2])): add_pass(sys.argv[2]) else: print("No user by the name of %s", %(sys.argv[2])) elif(sys.argv[1] == "help"): Help() else: do_nothing() if __name__ == "__main__": main()