Password managers like "Dashlane" etc. are popular these days and I understand why - with the multiples of accounts and whatnots that needs updated password on a regular basis.
So a couple of months ago I created my own password manager inspired by a couple of exercises from the popular "learn Python yourself"-book "Automate The Boring Stuff With Python" by Al Sweigart. I wanted to create a proper .exe file and make a program and not only run scripts in my coding environment. Back then (and now still) I've mostly used Python and R to make graphs out of data and playing around a bit with some machine learning models.
But it turned out that it was more complicated than I thought to create executables that included modules that had to be installed - so I ended up creating a tic-tac-toe-game instead for my first executable program. A setback sure, but it is what it is.
Earlier today I revisited my password manager and made a few changes. It's nothing fancy - and it only runs locally which makes it not so useful (i.e totally useless) for accounts being used on more than one unit - that unit being the one running the script, since it stores the passwords locally.
Anyway, I thought I'd share it and if someone wanted to use it or explain to me how I could do this a million times smarter, it'd be more than ok!
The password manager uses 4 functions. One that generates a random password (11-14 characters long) where the user can choose if he/she want's to include special characters or not.
A function where the user can assign a random password to an account, change a password, list all stored accounts and extract a saved password making it magically appear when the user uses the "paste" function!
And functions to encode and decode the passwords into a very sneaky way (The Unicode code point of each of the characters) before saving it on the drive.
'''
This is a program used to create new passwords
'''
def randomPassword():
import random
import string
print("Use special characters? Input \'No\' to not use special characters")
char = input()
char = char.lower()
letters, digits, special, Range = 0, 0, 0, range(random.randint(11,14))
if char == "no":
string = string.ascii_letters + string.digits
while letters < 2 and digits < 2:
pw = "".join([random.choice(string) for c in Range])
for c in pw:
if c.isalpha():
letters += 1
else:
digits += 1
else:
string = string.ascii_letters + string.digits + string.punctuation
while letters < 2 and digits < 2 and special < 2:
pw = "".join([random.choice(string) for c in Range])
for c in pw:
if c.isalpha():
letters += 1
elif c.isdecimal():
digits += 1
else:
special +=1
return pw
def passwordAction(pw_dict):
import pyperclip
print("Would you like to:\n(1) Retrieve a password\n(2) Create a new password\n(3) Change an old password\n(4) List the current accounts")
choice = 0
while choice < 1 or choice > 4:
print("Please choose by inputting a number between 1 & 4.")
choice = input()
try:
choice = int(choice)
except ValueError:
choice = 0
if choice == 1:
print("Input which account you want to retrieve a password for:")
account = input().lower()
if account in pw_dict:
pyperclip.copy(pw_dict[account])
print("Your password can now be pasted")
else:
print("There is no account with that name, input (4) for a list of avaliable accounts.")
print("")
choice = 0
if choice == 2:
print("Input the name of your new account.")
account = input().lower()
if account not in pw_dict:
pw_dict[account] = randomPassword()
pyperclip.copy(pw_dict[account])
print("Your password is created and stored, use Paste to get it now")
else:
print("Account already created, would you like to change password? Write Yes to change password")
ans = input().lower()
if ans == "yes":
choice == 3
else:
choice == 0
if choice == 3:
print("Input the name of the account you want to change password on.")
account = input().lower()
if account in pw_dict:
pw_dict[account] = randomPassword()
pyperclip.copy(pw_dict[account])
print("Your new password is created and stored, use Paste to get it now")
else:
print("Account not created, would you like to create it? Write Yes to create a new account")
ans = input().lower()
if ans == "yes":
choice == 1
else:
choice == 0
if choice == 4:
print(list(pw_dict.keys()))
choice = 0
return pw_dict
def encode(pw_dict):
for k, v in pw_dict.items():
w = []
for char in v:
w.append(ord(char))
pw_dict[k] = w
def decode(pw_dict):
for k, v in pw_dict.items():
pw = ""
for item in v:
pw += chr(int(item))
pw_dict[k] = pw
The functions are called for in the main script by calling on the module pw which is saved in the same folder as this script which looks like the following: (And doesn't really include much more than opening the saved accounts (If there are any - otherwise it'll just tell the user to create some accounts).
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import pw
import shelve
#-- Read and decode the saved file.
try:
with shelve.open('much_secrets') as shelf:
pw_dict = shelf['pw_dict']
pw.decode(pw_dict)
except KeyError:
print("No passwords saved, please create your first password.")
print("")
pw_dict = {}
#-- Run the program.
while True:
pw.passwordAction(pw_dict)
print("Input anything to quit (or press 'Enter' to return to menu)")
boom = input()
if boom != "":
break
#-- Encode and save the new file
pw.encode(pw_dict)
with shelve.open('much_secrets') as shelf:
shelf['pw_dict'] = pw_dict
The result looks like this if I run it in the (none default!) terminal.
The user navigates by entering 1-4 and pressing Enter and then following the new instructions that pop up. This is how it would look it I first listed the saved accounts and then retrieved a password that was stored.
(The last row is first me using the (cmd+v) to paste the password and then writing out the arrow and capital letters.)
Thank you for reading it! And all feedback is good feedback! :)
Comments