# Python Tkinter login GUI with database

I created a simple login program that works how I wanted them to work. I separated the GUI and database codes into two different python files. I named the files as login.py and dbaseManip.py. The login.py consist of Tkinter syntax and all stuff related to GUI. On the other hand, dbaseManip.py holds the database related syntax such as the connection and the queries.

import tkinter as tk
from tkinter import messagebox
from tkinter import ttk

import dbaseManip as db

def __init__(self,parent,*arags,**kwargs):
tk.Frame.__init__(self,parent)
self.parent = parent

self.parent.protocol("WM_DELETE_WINDOW",self.closing_window)

window_width = 350
window_height = 100
screen_width = self.parent.winfo_screenwidth()
screen_height = self.parent.winfo_screenheight()

x_position = int((screen_width/2) - (window_width/2))
y_position = int((screen_height/2) - (window_height/2))

self.parent.geometry("{}x{}+{}+{}".format(window_width,window_height,x_position,y_position))

self.widgeter()

def widgeter(self):

btn_exit = ttk.Button(self.parent,text="Exit",command=self.closing_window)

btn_exit.grid(row=2,column=1,sticky="nse")

def closing_window(self):
self.parent.destroy()

def submit(self):
__str_verify = str(__verify)
if __str_verify == "correct":
self.initialize_mainApplication()
elif __str_verify is "incorrect":
elif __str_verify == "notexist":

def initialize_mainApplication(self):
self.parent.destroy()
self.parent = tk.Tk()
self.mainApp = mainApplicaiton(self.parent)
self.parent.mainloop()

class mainApplicaiton(tk.Frame):
def __init__(self,parent):
self.parent = parent

if __name__ == "__main__":
root = tk.Tk()
root.mainloop()


dbaseManip.py

import mysql.connector

class DatabaseManip():
#

self.dbaseInitializer()

def dbaseInitializer(self):
mydb = mysql.connector.connect(
host="127.0.0.1",
user="root",
database="testdb"
)

self.myCursor = mydb.cursor()
query_user_exists = "SELECT EXISTS(SELECT * FROM users WHERE username = %s)"
tuple_user_exists = self.myCursor.fetchone()
total_user_exists = int(tuple_user_exists[0])

if total_user_exists != 0:
__tuple_valid_pass = self.myCursor.fetchone()

self.verdict = "correct"
else:
self.verdict = "incorrect"

else:
self.verdict = "notexist"

def __str__(self):
return self.verdict

@property

@property


This is how the system works:

1. The login form will pop up
2. After the user submitting their username and password, it will call the class DatabaseManip() that exists in dbaseManip.py.
3. The DatabaseManip Class will validate the user's account.
4. HERE COMES MY PROBLEM If the username does not exist in the database, it will assign a string "notexist" to a class variable called verdict. If the password is wrong, it will assign "incorrect". And lastly, if the validation is correct; it will assign "correct".
5. The verdict result (which is either "correct","incorrect" or "notexist") will be returned to the GUI class in login.py using the __str__ method.
6. In the loginForm class, a conditional statement will determine if the verdict from the databaseManip class is either "correct","incorrect" or "notexist". If it is "correct", a new window will pop-up. On the other hand, if it is either "incorrect" or "notexist", it will show an error message.

I think my way of coding this is extremely bad in terms of security and integrity. I'm not confident in the "correct", "incorrect", and "notexit" part. I would like to ask for advice to make this program more secure and not as wacky as the current state.

Firstly I'd suggest following PEP8 and/or using an auto-formatter like black, but if it's just you working on it that is a bit less of an issue than if other people were involved. Suffice to say, most code follows that and it usually gets flagged first thing (because it's so noticeable).

Reading the code, is that all there is, you are able to log in via a GUI? Then I'd say first thing would probably be not to hardcode the credentials to the database. So what/how's this securing anything? If the program has the credentials ... and the program is being run by the user who's authenticating ... what stops me from connecting directly to the database?

Apart from that fundamental issue looks mostly okay, no SQL injection since the execute will handle that.

__ as prefix for the variable names is unnecessary and confusing. I can't see why it's there at all.

Actually, SELECT password ... ... the password's stored in plaintext? Big no-no in anything used by other people. Do not store passwords in plaintext.

The properties at the end of DatabaseManip seem not very useful, in Python there's no need for them unless you want to control what/how values are stored in the object / how they're computed if they're not stored at all.

The __str__ method is there for what reason? That's very much confusing the responsibility of the class. It would somewhat make sense if it's being used interactively in a REPL, otherwise I can't see the reason for having it. Oh. Oh now I see it. Yeah, don't do that, that's bad style. How I'd expect things to go is something like this:

    def submit(self):
if result == "correct":
self.initialize_mainApplication()
elif result == "incorrect":
elif result == "notexist":
else:
messagebox.showerror("Unexpected validation result","Validation of credentials failed unexpectedly with result".format(result))


So here: Validating is an action, a method. The parameters of which aren't part of the helper object, but method parameters. The result is still a string (try making this an enumeration, that's more "correct" in a way as you really want to have a fixed set of possible results, not a string that can contain basically anything. Finally, the programmer error case is handled too (the last else).

Also note that ... is "foo" is likely incorrect, c.f. "foo" is "foobar"[0:3], is does a check for object identity, not equality! Not even numbers are same via is if they're not interned at the same time:

1000000 == 1000000 # _always_ True

x = 1000000
y = 1000000
x is y # _probably_ False


Also if x == True can obviously be simplified to if x.

So it's not all bad, simply try and stay away from "stringly"-typed things, use the language features as they're intended and have a goal for what your security requirements are. I've not gone into more detail on the last bit simply because I still don't understand the intent here. Suffice to say like this it would only work if the user can't exit the UI and open a shell / other means of executing code on the machine (like in a kiosk configuration with limited access to peripherals and the machine itself). Or if the actual database access was moved to a separate external service that (again) can't be circumvented by the local user.