Password Vault Screen using Tkinter

In the last part, we covered the basic authentication part of the application. In this part, we're going to build the Password Vault Screen.

Vault Methods

There will be a few buttons like Add Password , Update Password, and Delete Password in the password vault screen. These buttons when clicked will call some specific methods. Let's create those methods:

from tkinter import simpledialog
from database import init_database

class VaultMethods:

    def __init__ (self):
        self.db, self.cursor = init_database()

    def popup_entry(self, heading):
        answer = simpledialog.askstring("Enter details", heading)
        return answer

    def add_password(self, vault_screen):
        platform = self.popup_entry("Platform")
        userid = self.popup_entry("Username/Email")
        password = self.popup_entry("Password")

        insert_cmd = """INSERT INTO vault(platform, userid, password) VALUES (?, ?, ?)"""
        self.cursor.execute(insert_cmd, (platform, userid, password))
        self.db.commit()
        vault_screen()

    def update_password(self, id, vault_screen):
        password = self.popup_entry("Enter New Password")
        self.cursor.execute(
            "UPDATE vault SET password = ? WHERE id = ?", (password, id))
        self.db.commit()
        vault_screen()

    def remove_password(self, id, vault_screen):
        self.cursor.execute("DELETE FROM vault WHERE id = ?", (id,))
        self.db.commit()
        vault_screen()

In the above script, we are using simpledialogto create popups. Whenever any of the buttons will be clicked, the user will see a popup asking for some information. We have created a VaultMethod class in which we'll have all the methods. In the constructor, we are getting the dband cursorobjects.

The first method is called popup_entry(). We have created this method as a shortcut to create popups. This method takes a heading as an argument. We're using askstringmethod for creating the popup. We then return the value entered in the popup input field.

The next method is add_password() that takes the vault screen as an argument. Whenever we are adding a new password, we need three details - Platform Name , Username/Email , and Password. So, we need to create three popups for the same. We'll create the popups using the method created above. After we get the three corresponding values from these popups, we add this data into the database using the insert_cmd. We then show the vault_screen() again to the user.

The next method is update_password() that takes the id(from the database) of the entry and vault screen as the arguments. It then asks for a new password using the popup method. Once we get the value of the new password, we execute another database command to update the password for the id provided. We then show the vault_screen() again to the user.

The last method is remove_password() that again takes the id(from the database) of the entry and vault screen as the arguments. In this method, we just delete the entry that matches the id provided. We then show the vault_screen() again to the user.

3. Password Vault Screen

This is the main screen of the application where users will be able to add new passwords, modify previously saved passwords, delete passwords and copy passwords.

def password_vault_screen(self):
    for widget in self.window.winfo_children():
        widget.destroy()

    vault_methods = VaultMethods()

    self.window.geometry("850x350")
    main_frame = Frame(self.window)
    main_frame.pack(fill=BOTH, expand=1)

    main_canvas = Canvas(main_frame)
    main_canvas.pack(side=LEFT, fill=BOTH, expand=1)

    main_scrollbar = Scrollbar(main_frame, orient=VERTICAL, command=main_canvas.yview)
    main_scrollbar.pack(side=RIGHT, fill=Y)

    main_canvas.configure(yscrollcommand=main_scrollbar.set)
    main_canvas.bind('<Configure>', lambda e: main_canvas.configure(
            scrollregion=main_canvas.bbox("all")))

    second_frame = Frame(main_canvas)
    main_canvas.create_window((0, 0), window=second_frame, anchor="nw")

    generate_password_btn = Button(second_frame, text="Generate Password",
                                       command=PasswordGenerator)
    generate_password_btn.grid(row=1, column=2, pady=10)

    add_password_btn = Button(
            second_frame, text="Add New Password", command=partial(vault_methods.add_password, self.password_vault_screen))
    add_password_btn.grid(row=1, column=3, pady=10)

    lbl = Label(second_frame, text="Platform")
    lbl.grid(row=2, column=0, padx=40, pady=10)
    lbl = Label(second_frame, text="Email/Username")
    lbl.grid(row=2, column=1, padx=40, pady=10)
    lbl = Label(second_frame, text="Password")
    lbl.grid(row=2, column=2, padx=40, pady=10)

    self.cursor.execute("SELECT * FROM vault")

    if self.cursor.fetchall():
        i = 0
        while True:
            self.cursor.execute("SELECT * FROM vault")
            array = self.cursor.fetchall()

            platform_label = Label(second_frame, text=(array[i][1]))
            platform_label.grid(column=0, row=i + 3)

            account_label = Label(second_frame, text=(array[i][2]))
            account_label.grid(column=1, row=i + 3)

            password_label = Label(second_frame, text=(array[i][3]))
            password_label.grid(column=2, row=i + 3)

            copy_btn = Button(second_frame, text="Copy Password",
                                  command=partial(self.copy_text, array[i][3]))
            copy_btn.grid(column=3, row=i + 3, pady=10, padx=10)
            update_btn = Button(second_frame, text="Update Password",
                                    command=partial(vault_methods.update_password, array[i][0], self.password_vault_screen))
            update_btn.grid(column=4, row=i + 3, pady=10, padx=10)
            remove_btn = Button(second_frame, text="Delete Password",
                                    command=partial(vault_methods.remove_password, array[i][0], self.password_vault_screen))
            remove_btn.grid(column=5, row=i + 3, pady=10, padx=10)

            i += 1

            self.cursor.execute("SELECT * FROM vault")
            if len(self.cursor.fetchall()) <= i:
                break

In the above script, first, we destroy all the other opened widgets(if any). We then create a vault_methodobject of the VaultMethod class. We are then creating a frame and canvas inside that frame. Further, we are creating a scrollbar which we might need if we have too many passwords.

Next, we are creating another frame where we'll put our buttons and data. In the first row, we'll have two buttons - Generate Password and Add Password. Generate Password button, when clicked, will call the password generator that we had built in the first part of the series. The Add New Password button will call the add_password() method from the VaultMethod class.

Next in the second row, we'll have three labels - Platform , Email/Username , and Password. After this, we have to render the data from the database in the upcoming rows. So, we need to fetch all the data. We are using a while loop and an iterator i. All the data is stored in a variable called array. The array will look like this:

[(1, 'Facebook', 'ashutosh', '3ftF%IkoQJ'), (2, 'Gmail', 'ashutosh', 'Hello@123')]

If you notice, the array is a list of tuples. Each tuple has four elements - id, Platform Name, Username/Email, and Password.

Now, within the loop, we are creating corresponding labels for each of them. The first column, i.e., the platform name will be given by array[i][1]. Similarly, the second column is the username/email field given by array[i][2] and the third column is the password field given by array[i][3]. The rows will be changing accordingly for each iteration. Since the first data should be placed in the third row, it can be written as row=i+3, where i=0 for the first iteration. Also for each column, we have three buttons - Copy Password , Update Password , and Delete Password. These buttons will be placed in the same rows, but the value of columns will be 3, 4, and 5 respectively. These buttons will call their methods as defined in the VaultMethod class. After we are done with one row, we increment the value of i by 1 to move to the next row.

If the number of data from the database is less than or equal to the value of i, we break the loop immediately.

Demo

Conclusion

This was the final blog of this series. You can further add more features to this application such as Forgot Master Password. This application can be converted to an executable application that can be run on any machine whether Python is installed there or not. Hope you loved this series!

23