top of page
Search

Password Manager in Python

Writer's picture: David RaxénDavid Raxén

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! :)

47 views0 comments

Recent Posts

See All

Comments


©2019 by David Raxén. Proudly created with Wix.com

bottom of page